Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9731fa35d8 | ||
|
|
53be4db22b | ||
|
|
0202fa2ca3 | ||
|
|
d5262b5474 | ||
|
|
cb2e1d54c2 | ||
|
|
6392297a27 | ||
|
|
6001d4eba3 | ||
|
|
79588e4bbc | ||
|
|
2b21c38382 | ||
|
|
481d25845e | ||
|
|
e0f8bfe283 | ||
|
|
d2ecb01358 | ||
|
|
316e793b1e | ||
|
|
6df6809ab3 | ||
|
|
c71f892601 | ||
|
|
d0b5a16ce7 | ||
|
|
84638d3228 | ||
|
|
bb21a2aa5f | ||
|
|
c37c948129 | ||
|
|
5155476dd7 | ||
|
|
7ef4f60309 | ||
|
|
b0865cbbdc | ||
|
|
990c1070e2 | ||
|
|
65bdd413eb | ||
|
|
60fa35eb73 | ||
|
|
32cfd5c233 | ||
|
|
7852495527 | ||
|
|
3679a78f47 | ||
|
|
6b21568408 | ||
|
|
04a5aa41d7 | ||
|
|
fea1a2199c | ||
|
|
9c8492efb9 | ||
|
|
20b89a8ddd | ||
|
|
5a8e281fb1 | ||
|
|
a9bb413199 | ||
|
|
428d8ab1b1 | ||
|
|
c2675bcdb6 | ||
|
|
1fe228e4c0 | ||
|
|
c5a6497f10 | ||
|
|
f25a82585f | ||
|
|
01209b66ac | ||
|
|
4e19817d6f | ||
|
|
a48adff8ac |
@@ -1,9 +1,9 @@
|
|||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = "0.5.0"
|
Version = "0.5.2"
|
||||||
|
|
||||||
APINodeVersion = "0.5.0"
|
APINodeVersion = "0.5.2"
|
||||||
|
|
||||||
ProductName = "Edge Admin"
|
ProductName = "Edge Admin"
|
||||||
ProcessName = "edge-admin"
|
ProcessName = "edge-admin"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 生成Token
|
// Generate 生成Token
|
||||||
func Generate() string {
|
func Generate() string {
|
||||||
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
|
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ func Generate() string {
|
|||||||
return token
|
return token
|
||||||
}
|
}
|
||||||
|
|
||||||
// 校验Token
|
// Validate 校验Token
|
||||||
func Validate(token string) (b bool) {
|
func Validate(token string) (b bool) {
|
||||||
if len(token) == 0 {
|
if len(token) == 0 {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"github.com/iwind/TeaGo/rands"
|
"github.com/iwind/TeaGo/rands"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@@ -19,7 +20,9 @@ import (
|
|||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
"google.golang.org/grpc/encoding/gzip"
|
"google.golang.org/grpc/encoding/gzip"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -38,7 +41,7 @@ func NewRPCClient(apiConfig *configs.APIConfig, isPrimary bool) (*RPCClient, err
|
|||||||
return nil, errors.New("api config should not be nil")
|
return nil, errors.New("api config should not be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &RPCClient{
|
var client = &RPCClient{
|
||||||
apiConfig: apiConfig,
|
apiConfig: apiConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +126,10 @@ func (this *RPCClient) ServerRPC() pb.ServerServiceClient {
|
|||||||
return pb.NewServerServiceClient(this.pickConn())
|
return pb.NewServerServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) ServerBandwidthStatRPC() pb.ServerBandwidthStatServiceClient {
|
||||||
|
return pb.NewServerBandwidthStatServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) ServerClientSystemMonthlyStatRPC() pb.ServerClientSystemMonthlyStatServiceClient {
|
func (this *RPCClient) ServerClientSystemMonthlyStatRPC() pb.ServerClientSystemMonthlyStatServiceClient {
|
||||||
return pb.NewServerClientSystemMonthlyStatServiceClient(this.pickConn())
|
return pb.NewServerClientSystemMonthlyStatServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
@@ -320,6 +327,10 @@ func (this *RPCClient) IPLibraryFileRPC() pb.IPLibraryFileServiceClient {
|
|||||||
return pb.NewIPLibraryFileServiceClient(this.pickConn())
|
return pb.NewIPLibraryFileServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) IPLibraryArtifactRPC() pb.IPLibraryArtifactServiceClient {
|
||||||
|
return pb.NewIPLibraryArtifactServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) IPListRPC() pb.IPListServiceClient {
|
func (this *RPCClient) IPListRPC() pb.IPListServiceClient {
|
||||||
return pb.NewIPListServiceClient(this.pickConn())
|
return pb.NewIPListServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
@@ -486,8 +497,8 @@ func (this *RPCClient) TrafficDailyStatRPC() pb.TrafficDailyStatServiceClient {
|
|||||||
|
|
||||||
// Context 构造Admin上下文
|
// Context 构造Admin上下文
|
||||||
func (this *RPCClient) Context(adminId int64) context.Context {
|
func (this *RPCClient) Context(adminId int64) context.Context {
|
||||||
ctx := context.Background()
|
var ctx = context.Background()
|
||||||
m := maps.Map{
|
var m = maps.Map{
|
||||||
"timestamp": time.Now().Unix(),
|
"timestamp": time.Now().Unix(),
|
||||||
"type": "admin",
|
"type": "admin",
|
||||||
"userId": adminId,
|
"userId": adminId,
|
||||||
@@ -502,15 +513,15 @@ func (this *RPCClient) Context(adminId int64) context.Context {
|
|||||||
utils.PrintError(err)
|
utils.PrintError(err)
|
||||||
return context.Background()
|
return context.Background()
|
||||||
}
|
}
|
||||||
token := base64.StdEncoding.EncodeToString(data)
|
var token = base64.StdEncoding.EncodeToString(data)
|
||||||
ctx = metadata.AppendToOutgoingContext(ctx, "nodeId", this.apiConfig.NodeId, "token", token)
|
ctx = metadata.AppendToOutgoingContext(ctx, "nodeId", this.apiConfig.NodeId, "token", token)
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
// APIContext 构造API上下文
|
// APIContext 构造API上下文
|
||||||
func (this *RPCClient) APIContext(apiNodeId int64) context.Context {
|
func (this *RPCClient) APIContext(apiNodeId int64) context.Context {
|
||||||
ctx := context.Background()
|
var ctx = context.Background()
|
||||||
m := maps.Map{
|
var m = maps.Map{
|
||||||
"timestamp": time.Now().Unix(),
|
"timestamp": time.Now().Unix(),
|
||||||
"type": "api",
|
"type": "api",
|
||||||
"userId": apiNodeId,
|
"userId": apiNodeId,
|
||||||
@@ -525,7 +536,7 @@ func (this *RPCClient) APIContext(apiNodeId int64) context.Context {
|
|||||||
utils.PrintError(err)
|
utils.PrintError(err)
|
||||||
return context.Background()
|
return context.Background()
|
||||||
}
|
}
|
||||||
token := base64.StdEncoding.EncodeToString(data)
|
var token = base64.StdEncoding.EncodeToString(data)
|
||||||
ctx = metadata.AppendToOutgoingContext(ctx, "nodeId", this.apiConfig.NodeId, "token", token)
|
ctx = metadata.AppendToOutgoingContext(ctx, "nodeId", this.apiConfig.NodeId, "token", token)
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
@@ -542,20 +553,39 @@ func (this *RPCClient) UpdateConfig(config *configs.APIConfig) error {
|
|||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
func (this *RPCClient) init() error {
|
func (this *RPCClient) init() error {
|
||||||
|
// 当前的IP地址
|
||||||
|
var localIPAddrs = this.localIPAddrs()
|
||||||
|
|
||||||
// 重新连接
|
// 重新连接
|
||||||
conns := []*grpc.ClientConn{}
|
var conns = []*grpc.ClientConn{}
|
||||||
for _, endpoint := range this.apiConfig.RPC.Endpoints {
|
for _, endpoint := range this.apiConfig.RPC.Endpoints {
|
||||||
u, err := url.Parse(endpoint)
|
u, err := url.Parse(endpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("parse endpoint failed: " + err.Error())
|
return errors.New("parse endpoint failed: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var apiHost = u.Host
|
||||||
|
|
||||||
|
// 如果本机,则将地址修改为回路地址
|
||||||
|
if lists.ContainsString(localIPAddrs, u.Hostname()) {
|
||||||
|
if strings.Contains(apiHost, "[") { // IPv6 [host]:port
|
||||||
|
apiHost = "[::1]"
|
||||||
|
} else {
|
||||||
|
apiHost = "127.0.0.1"
|
||||||
|
}
|
||||||
|
var port = u.Port()
|
||||||
|
if len(port) > 0 {
|
||||||
|
apiHost += ":" + port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var conn *grpc.ClientConn
|
var conn *grpc.ClientConn
|
||||||
var callOptions = grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(128*1024*1024),
|
var callOptions = grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(128*1024*1024),
|
||||||
grpc.UseCompressor(gzip.Name))
|
grpc.UseCompressor(gzip.Name))
|
||||||
if u.Scheme == "http" {
|
if u.Scheme == "http" {
|
||||||
conn, err = grpc.Dial(u.Host, grpc.WithTransportCredentials(insecure.NewCredentials()), callOptions)
|
conn, err = grpc.Dial(apiHost, grpc.WithTransportCredentials(insecure.NewCredentials()), callOptions)
|
||||||
} else if u.Scheme == "https" {
|
} else if u.Scheme == "https" {
|
||||||
conn, err = grpc.Dial(u.Host, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
|
conn, err = grpc.Dial(apiHost, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
})), callOptions)
|
})), callOptions)
|
||||||
} else {
|
} else {
|
||||||
@@ -582,7 +612,7 @@ func (this *RPCClient) pickConn() *grpc.ClientConn {
|
|||||||
|
|
||||||
// 检查连接状态
|
// 检查连接状态
|
||||||
if len(this.conns) > 0 {
|
if len(this.conns) > 0 {
|
||||||
availableConns := []*grpc.ClientConn{}
|
var availableConns = []*grpc.ClientConn{}
|
||||||
for _, state := range []connectivity.State{connectivity.Ready, connectivity.Idle, connectivity.Connecting} {
|
for _, state := range []connectivity.State{connectivity.Ready, connectivity.Idle, connectivity.Connecting} {
|
||||||
for _, conn := range this.conns {
|
for _, conn := range this.conns {
|
||||||
if conn.GetState() == state {
|
if conn.GetState() == state {
|
||||||
@@ -634,3 +664,18 @@ func (this *RPCClient) Close() error {
|
|||||||
|
|
||||||
return lastErr
|
return lastErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) localIPAddrs() []string {
|
||||||
|
localInterfaceAddrs, err := net.InterfaceAddrs()
|
||||||
|
var localIPAddrs = []string{}
|
||||||
|
if err == nil {
|
||||||
|
for _, addr := range localInterfaceAddrs {
|
||||||
|
var addrString = addr.String()
|
||||||
|
var index = strings.Index(addrString, "/")
|
||||||
|
if index > 0 {
|
||||||
|
localIPAddrs = append(localIPAddrs, addrString[:index])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return localIPAddrs
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ func TestRPCClient_NodeRPC(t *testing.T) {
|
|||||||
func TestRPC_Dial_HTTP(t *testing.T) {
|
func TestRPC_Dial_HTTP(t *testing.T) {
|
||||||
client, err := NewRPCClient(&configs.APIConfig{
|
client, err := NewRPCClient(&configs.APIConfig{
|
||||||
RPC: struct {
|
RPC: struct {
|
||||||
Endpoints []string `yaml:"endpoints"`
|
Endpoints []string `yaml:"endpoints"`
|
||||||
|
DisableUpdate bool `yaml:"disableUpdate"`
|
||||||
}{
|
}{
|
||||||
Endpoints: []string{"http://127.0.0.1:8004"},
|
Endpoints: []string{"http://127.0.0.1:8004"},
|
||||||
},
|
},
|
||||||
@@ -56,7 +57,8 @@ func TestRPC_Dial_HTTP(t *testing.T) {
|
|||||||
func TestRPC_Dial_HTTP_2(t *testing.T) {
|
func TestRPC_Dial_HTTP_2(t *testing.T) {
|
||||||
client, err := NewRPCClient(&configs.APIConfig{
|
client, err := NewRPCClient(&configs.APIConfig{
|
||||||
RPC: struct {
|
RPC: struct {
|
||||||
Endpoints []string `yaml:"endpoints"`
|
Endpoints []string `yaml:"endpoints"`
|
||||||
|
DisableUpdate bool `yaml:"disableUpdate"`
|
||||||
}{
|
}{
|
||||||
Endpoints: []string{"https://127.0.0.1:8003"},
|
Endpoints: []string{"https://127.0.0.1:8003"},
|
||||||
},
|
},
|
||||||
@@ -77,7 +79,8 @@ func TestRPC_Dial_HTTP_2(t *testing.T) {
|
|||||||
func TestRPC_Dial_HTTPS(t *testing.T) {
|
func TestRPC_Dial_HTTPS(t *testing.T) {
|
||||||
client, err := NewRPCClient(&configs.APIConfig{
|
client, err := NewRPCClient(&configs.APIConfig{
|
||||||
RPC: struct {
|
RPC: struct {
|
||||||
Endpoints []string `yaml:"endpoints"`
|
Endpoints []string `yaml:"endpoints"`
|
||||||
|
DisableUpdate bool `yaml:"disableUpdate"`
|
||||||
}{
|
}{
|
||||||
Endpoints: []string{"https://127.0.0.1:8004"},
|
Endpoints: []string{"https://127.0.0.1:8004"},
|
||||||
},
|
},
|
||||||
@@ -94,3 +97,53 @@ func TestRPC_Dial_HTTPS(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Log(resp.Node)
|
t.Log(resp.Node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkNewRPCClient(b *testing.B) {
|
||||||
|
config, err := configs.LoadAPIConfig()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
rpc, err := NewRPCClient(config, true)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
resp, err := rpc.AdminRPC().LoginAdmin(rpc.Context(0), &pb.LoginAdminRequest{
|
||||||
|
Username: "admin",
|
||||||
|
Password: stringutil.Md5("123456"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
_ = resp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkNewRPCClient_2(b *testing.B) {
|
||||||
|
config, err := configs.LoadAPIConfig()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
rpc, err := NewRPCClient(config, true)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var conn = rpc.AdminRPC()
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
resp, err := conn.LoginAdmin(rpc.Context(0), &pb.LoginAdminRequest{
|
||||||
|
Username: "admin",
|
||||||
|
Password: stringutil.Md5("123456"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
_ = resp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// format address
|
// FormatAddress format address
|
||||||
func FormatAddress(addr string) string {
|
func FormatAddress(addr string) string {
|
||||||
if strings.HasSuffix(addr, "unix:") {
|
if strings.HasSuffix(addr, "unix:") {
|
||||||
return addr
|
return addr
|
||||||
@@ -17,7 +17,7 @@ func FormatAddress(addr string) string {
|
|||||||
return addr
|
return addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分割数字
|
// SplitNumbers 分割数字
|
||||||
func SplitNumbers(numbers string) (result []int64) {
|
func SplitNumbers(numbers string) (result []int64) {
|
||||||
if len(numbers) == 0 {
|
if len(numbers) == 0 {
|
||||||
return
|
return
|
||||||
|
|||||||
67
internal/utils/strings_stream.go
Normal file
67
internal/utils/strings_stream.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FilterNotEmpty(item string) bool {
|
||||||
|
return len(item) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func MapAddPrefixFunc(prefix string) func(item string) string {
|
||||||
|
return func(item string) string {
|
||||||
|
if !strings.HasPrefix(item, prefix) {
|
||||||
|
return prefix + item
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type StringsStream struct {
|
||||||
|
s []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStringsStream(s []string) *StringsStream {
|
||||||
|
return &StringsStream{s: s}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *StringsStream) Map(f ...func(item string) string) *StringsStream {
|
||||||
|
for index, item := range this.s {
|
||||||
|
for _, f1 := range f {
|
||||||
|
item = f1(item)
|
||||||
|
}
|
||||||
|
this.s[index] = item
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *StringsStream) Filter(f ...func(item string) bool) *StringsStream {
|
||||||
|
for _, f1 := range f {
|
||||||
|
var newStrings = []string{}
|
||||||
|
for _, item := range this.s {
|
||||||
|
if f1(item) {
|
||||||
|
newStrings = append(newStrings, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.s = newStrings
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *StringsStream) Unique() *StringsStream {
|
||||||
|
var newStrings = []string{}
|
||||||
|
for _, item := range this.s {
|
||||||
|
if !lists.ContainsString(newStrings, item) {
|
||||||
|
newStrings = append(newStrings, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.s = newStrings
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *StringsStream) Result() []string {
|
||||||
|
return this.s
|
||||||
|
}
|
||||||
25
internal/utils/strings_stream_test.go
Normal file
25
internal/utils/strings_stream_test.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package utils_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStringsStream_Filter(t *testing.T) {
|
||||||
|
var stream = utils.NewStringsStream([]string{"a", "b", "1", "2", "", "png", "a"})
|
||||||
|
stream.Filter(func(item string) bool {
|
||||||
|
return len(item) > 0
|
||||||
|
})
|
||||||
|
t.Log(stream.Result())
|
||||||
|
stream.Map(func(item string) string {
|
||||||
|
return "." + item
|
||||||
|
})
|
||||||
|
t.Log(stream.Result())
|
||||||
|
stream.Unique()
|
||||||
|
t.Log(stream.Result())
|
||||||
|
stream.Map(strings.ToUpper, strings.ToLower)
|
||||||
|
t.Log(stream.Result())
|
||||||
|
}
|
||||||
@@ -25,7 +25,8 @@ func (this *DetailAction) Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *DetailAction) RunGet(params struct {
|
func (this *DetailAction) RunGet(params struct {
|
||||||
NodeId int64
|
NodeId int64
|
||||||
|
ClusterId int64
|
||||||
}) {
|
}) {
|
||||||
this.Data["nodeId"] = params.NodeId
|
this.Data["nodeId"] = params.NodeId
|
||||||
|
|
||||||
@@ -43,13 +44,13 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
// 主集群
|
// 主集群
|
||||||
var clusterMap maps.Map = nil
|
var clusterMap maps.Map = nil
|
||||||
if node.NodeCluster != nil {
|
if node.NodeCluster != nil {
|
||||||
clusterId := node.NodeCluster.Id
|
var clusterId = node.NodeCluster.Id
|
||||||
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: clusterId})
|
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: clusterId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cluster := clusterResp.NodeCluster
|
var cluster = clusterResp.NodeCluster
|
||||||
if cluster != nil {
|
if cluster != nil {
|
||||||
clusterMap = maps.Map{
|
clusterMap = maps.Map{
|
||||||
"id": cluster.Id,
|
"id": cluster.Id,
|
||||||
@@ -69,6 +70,14 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 当前访问集群的DNS设置
|
||||||
|
clusterDNSInfo, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["dnsIsExcludingLnNode"] = clusterDNSInfo != nil && !clusterDNSInfo.IncludingLnNodes && node.Level > 1
|
||||||
|
|
||||||
// IP地址
|
// IP地址
|
||||||
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
|
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
|
||||||
NodeId: params.NodeId,
|
NodeId: params.NodeId,
|
||||||
@@ -286,6 +295,11 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lnAddrs = node.LnAddrs
|
||||||
|
if lnAddrs == nil {
|
||||||
|
lnAddrs = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
this.Data["node"] = maps.Map{
|
this.Data["node"] = maps.Map{
|
||||||
"id": node.Id,
|
"id": node.Id,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
@@ -303,6 +317,7 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
"routes": routeMaps,
|
"routes": routeMaps,
|
||||||
"level": node.Level,
|
"level": node.Level,
|
||||||
"levelInfo": nodeconfigs.FindNodeLevel(int(node.Level)),
|
"levelInfo": nodeconfigs.FindNodeLevel(int(node.Level)),
|
||||||
|
"lnAddrs": lnAddrs,
|
||||||
|
|
||||||
"status": maps.Map{
|
"status": maps.Map{
|
||||||
"isActive": status.IsActive,
|
"isActive": status.IsActive,
|
||||||
|
|||||||
@@ -102,8 +102,12 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
this.FailField("tcpMaxConnectionsPerIP", "TCP: 单IP TCP最大连接数不能小于"+types.String(nodeconfigs.DefaultTCPMinConnectionsPerIP))
|
this.FailField("tcpMaxConnectionsPerIP", "TCP: 单IP TCP最大连接数不能小于"+types.String(nodeconfigs.DefaultTCPMinConnectionsPerIP))
|
||||||
}
|
}
|
||||||
|
|
||||||
if tcpConfig.NewConnectionsRate > 0 && tcpConfig.NewConnectionsRate < nodeconfigs.DefaultTCPNewConnectionsMinRate {
|
if tcpConfig.NewConnectionsMinutelyRate > 0 && tcpConfig.NewConnectionsMinutelyRate < nodeconfigs.DefaultTCPNewConnectionsMinMinutelyRate {
|
||||||
this.FailField("tcpNewConnectionsRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinRate))
|
this.FailField("tcpNewConnectionsMinutelyRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinMinutelyRate))
|
||||||
|
}
|
||||||
|
|
||||||
|
if tcpConfig.NewConnectionsSecondlyRate > 0 && tcpConfig.NewConnectionsSecondlyRate < nodeconfigs.DefaultTCPNewConnectionsMinSecondlyRate {
|
||||||
|
this.FailField("tcpNewConnectionsSecondlyRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinSecondlyRate))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Port
|
// Port
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UpdateAction struct {
|
type UpdateAction struct {
|
||||||
@@ -61,7 +62,7 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ipAddressMaps := []maps.Map{}
|
var ipAddressMaps = []maps.Map{}
|
||||||
for _, addr := range ipAddressesResp.NodeIPAddresses {
|
for _, addr := range ipAddressesResp.NodeIPAddresses {
|
||||||
thresholds, err := ipaddressutils.InitNodeIPAddressThresholds(this.Parent(), addr.Id)
|
thresholds, err := ipaddressutils.InitNodeIPAddressThresholds(this.Parent(), addr.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -109,6 +110,12 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
"level": node.Level,
|
"level": node.Level,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if node.LnAddrs == nil {
|
||||||
|
nodeMap["lnAddrs"] = []string{}
|
||||||
|
} else {
|
||||||
|
nodeMap["lnAddrs"] = node.LnAddrs
|
||||||
|
}
|
||||||
|
|
||||||
if node.NodeCluster != nil {
|
if node.NodeCluster != nil {
|
||||||
nodeMap["primaryCluster"] = maps.Map{
|
nodeMap["primaryCluster"] = maps.Map{
|
||||||
"id": node.NodeCluster.Id,
|
"id": node.NodeCluster.Id,
|
||||||
@@ -149,6 +156,7 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
SecondaryClusterIds []byte
|
SecondaryClusterIds []byte
|
||||||
IsOn bool
|
IsOn bool
|
||||||
Level int32
|
Level int32
|
||||||
|
LnAddrs []string
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
}) {
|
}) {
|
||||||
@@ -178,7 +186,7 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IP地址
|
// IP地址
|
||||||
ipAddresses := []maps.Map{}
|
var ipAddresses = []maps.Map{}
|
||||||
if len(params.IPAddressesJSON) > 0 {
|
if len(params.IPAddressesJSON) > 0 {
|
||||||
err := json.Unmarshal(params.IPAddressesJSON, &ipAddresses)
|
err := json.Unmarshal(params.IPAddressesJSON, &ipAddresses)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -195,6 +203,27 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
this.Fail("没有权限修改节点级别:" + types.String(params.Level))
|
this.Fail("没有权限修改节点级别:" + types.String(params.Level))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查Ln节点地址
|
||||||
|
var lnAddrs = []string{}
|
||||||
|
if params.Level > 1 {
|
||||||
|
for _, lnAddr := range params.LnAddrs {
|
||||||
|
if len(lnAddr) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理 host:port
|
||||||
|
host, _, err := net.SplitHostPort(lnAddr)
|
||||||
|
if err == nil {
|
||||||
|
lnAddr = host
|
||||||
|
}
|
||||||
|
|
||||||
|
if net.ParseIP(lnAddr) == nil {
|
||||||
|
this.Fail("L2级别访问地址 '" + lnAddr + "' 格式错误,请纠正后再提交")
|
||||||
|
}
|
||||||
|
lnAddrs = append(lnAddrs, lnAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_, err := this.RPC().NodeRPC().UpdateNode(this.AdminContext(), &pb.UpdateNodeRequest{
|
_, err := this.RPC().NodeRPC().UpdateNode(this.AdminContext(), &pb.UpdateNodeRequest{
|
||||||
NodeId: params.NodeId,
|
NodeId: params.NodeId,
|
||||||
NodeGroupId: params.GroupId,
|
NodeGroupId: params.GroupId,
|
||||||
@@ -204,6 +233,7 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
SecondaryNodeClusterIds: secondaryClusterIds,
|
SecondaryNodeClusterIds: secondaryClusterIds,
|
||||||
IsOn: params.IsOn,
|
IsOn: params.IsOn,
|
||||||
Level: params.Level,
|
Level: params.Level,
|
||||||
|
LnAddrs: lnAddrs,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -75,8 +75,12 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
this.FailField("tcpMaxConnectionsPerIP", "TCP: 单IP TCP最大连接数不能小于"+types.String(nodeconfigs.DefaultTCPMinConnectionsPerIP))
|
this.FailField("tcpMaxConnectionsPerIP", "TCP: 单IP TCP最大连接数不能小于"+types.String(nodeconfigs.DefaultTCPMinConnectionsPerIP))
|
||||||
}
|
}
|
||||||
|
|
||||||
if tcpConfig.NewConnectionsRate > 0 && tcpConfig.NewConnectionsRate < nodeconfigs.DefaultTCPNewConnectionsMinRate {
|
if tcpConfig.NewConnectionsMinutelyRate > 0 && tcpConfig.NewConnectionsMinutelyRate < nodeconfigs.DefaultTCPNewConnectionsMinMinutelyRate {
|
||||||
this.FailField("tcpNewConnectionsRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinRate))
|
this.FailField("tcpNewConnectionsMinutelyRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinMinutelyRate))
|
||||||
|
}
|
||||||
|
|
||||||
|
if tcpConfig.NewConnectionsSecondlyRate > 0 && tcpConfig.NewConnectionsSecondlyRate < nodeconfigs.DefaultTCPNewConnectionsMinSecondlyRate {
|
||||||
|
this.FailField("tcpNewConnectionsSecondlyRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinSecondlyRate))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Port
|
// Port
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
this.Data["ttl"] = dnsInfoResp.Ttl
|
this.Data["ttl"] = dnsInfoResp.Ttl
|
||||||
this.Data["cnameAsDomain"] = dnsInfoResp.CnameAsDomain
|
this.Data["cnameAsDomain"] = dnsInfoResp.CnameAsDomain
|
||||||
|
this.Data["includingLnNodes"] = dnsInfoResp.IncludingLnNodes
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
@@ -60,13 +61,14 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
func (this *IndexAction) RunPost(params struct {
|
func (this *IndexAction) RunPost(params struct {
|
||||||
ClusterId int64
|
ClusterId int64
|
||||||
|
|
||||||
DnsDomainId int64
|
DnsDomainId int64
|
||||||
DnsName string
|
DnsName string
|
||||||
NodesAutoSync bool
|
NodesAutoSync bool
|
||||||
ServersAutoSync bool
|
ServersAutoSync bool
|
||||||
CnameRecords []string
|
CnameRecords []string
|
||||||
Ttl int32
|
Ttl int32
|
||||||
CnameAsDomain bool
|
CnameAsDomain bool
|
||||||
|
IncludingLnNodes bool
|
||||||
|
|
||||||
ConfirmResetDomain bool // 是否确认重置域名
|
ConfirmResetDomain bool // 是否确认重置域名
|
||||||
|
|
||||||
@@ -107,14 +109,15 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err := this.RPC().NodeClusterRPC().UpdateNodeClusterDNS(this.AdminContext(), &pb.UpdateNodeClusterDNSRequest{
|
_, err := this.RPC().NodeClusterRPC().UpdateNodeClusterDNS(this.AdminContext(), &pb.UpdateNodeClusterDNSRequest{
|
||||||
NodeClusterId: params.ClusterId,
|
NodeClusterId: params.ClusterId,
|
||||||
DnsName: params.DnsName,
|
DnsName: params.DnsName,
|
||||||
DnsDomainId: params.DnsDomainId,
|
DnsDomainId: params.DnsDomainId,
|
||||||
NodesAutoSync: params.NodesAutoSync,
|
NodesAutoSync: params.NodesAutoSync,
|
||||||
ServersAutoSync: params.ServersAutoSync,
|
ServersAutoSync: params.ServersAutoSync,
|
||||||
CnameRecords: params.CnameRecords,
|
CnameRecords: params.CnameRecords,
|
||||||
Ttl: params.Ttl,
|
Ttl: params.Ttl,
|
||||||
CnameAsDomain: params.CnameAsDomain,
|
CnameAsDomain: params.CnameAsDomain,
|
||||||
|
IncludingLnNodes: params.IncludingLnNodes,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package logs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -29,5 +30,8 @@ func (this *FixAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通知左侧数字Badge更新
|
||||||
|
helpers.NotifyNodeLogsCountChange()
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package logs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,5 +22,8 @@ func (this *FixAllAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通知左侧数字Badge更新
|
||||||
|
helpers.NotifyNodeLogsCountChange()
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,8 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var firstUnreadNodeMap maps.Map = nil
|
||||||
|
|
||||||
var logs = []maps.Map{}
|
var logs = []maps.Map{}
|
||||||
for _, log := range logsResp.NodeLogs {
|
for _, log := range logsResp.NodeLogs {
|
||||||
// 节点信息
|
// 节点信息
|
||||||
@@ -132,6 +134,13 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if params.Type == "unread" && firstUnreadNodeMap == nil {
|
||||||
|
firstUnreadNodeMap = maps.Map{
|
||||||
|
"id": node.Id,
|
||||||
|
"name": node.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 服务信息
|
// 服务信息
|
||||||
var serverMap = maps.Map{"id": 0}
|
var serverMap = maps.Map{"id": 0}
|
||||||
if log.ServerId > 0 {
|
if log.ServerId > 0 {
|
||||||
@@ -174,5 +183,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
this.Data["logs"] = logs
|
this.Data["logs"] = logs
|
||||||
|
|
||||||
|
this.Data["firstUnreadNode"] = firstUnreadNodeMap
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package logs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,5 +21,8 @@ func (this *ReadAllLogsAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通知左侧数字Badge更新
|
||||||
|
helpers.NotifyNodeLogsCountChange()
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ package logs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,14 +15,21 @@ type ReadLogsAction struct {
|
|||||||
|
|
||||||
func (this *ReadLogsAction) RunPost(params struct {
|
func (this *ReadLogsAction) RunPost(params struct {
|
||||||
LogIds []int64
|
LogIds []int64
|
||||||
|
|
||||||
|
NodeId int64
|
||||||
}) {
|
}) {
|
||||||
_, err := this.RPC().NodeLogRPC().UpdateNodeLogsRead(this.AdminContext(), &pb.UpdateNodeLogsReadRequest{
|
_, err := this.RPC().NodeLogRPC().UpdateNodeLogsRead(this.AdminContext(), &pb.UpdateNodeLogsReadRequest{
|
||||||
NodeLogIds: params.LogIds,
|
NodeLogIds: params.LogIds,
|
||||||
|
NodeId: params.NodeId,
|
||||||
|
Role: nodeconfigs.NodeRoleNode,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通知左侧数字Badge更新
|
||||||
|
helpers.NotifyNodeLogsCountChange()
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dashboard/dashboardutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dashboard/dashboardutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
@@ -25,6 +26,10 @@ func (this *IndexAction) Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *IndexAction) RunGet(params struct{}) {
|
func (this *IndexAction) RunGet(params struct{}) {
|
||||||
|
// 通知菜单数字Badge更新
|
||||||
|
helpers.NotifyIPItemsCountChanges()
|
||||||
|
helpers.NotifyNodeLogsCountChange()
|
||||||
|
|
||||||
if teaconst.IsPlus {
|
if teaconst.IsPlus {
|
||||||
this.RedirectURL("/dashboard/boards")
|
this.RedirectURL("/dashboard/boards")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -23,36 +23,38 @@ func (this *UpdateClusterPopupAction) RunGet(params struct {
|
|||||||
}) {
|
}) {
|
||||||
this.Data["clusterId"] = params.ClusterId
|
this.Data["clusterId"] = params.ClusterId
|
||||||
|
|
||||||
dnsResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
dnsInfoResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.Data["dnsName"] = dnsResp.Name
|
this.Data["dnsName"] = dnsInfoResp.Name
|
||||||
this.Data["nodesAutoSync"] = dnsResp.NodesAutoSync
|
this.Data["nodesAutoSync"] = dnsInfoResp.NodesAutoSync
|
||||||
this.Data["serversAutoSync"] = dnsResp.ServersAutoSync
|
this.Data["serversAutoSync"] = dnsInfoResp.ServersAutoSync
|
||||||
if dnsResp.Domain != nil {
|
if dnsInfoResp.Domain != nil {
|
||||||
this.Data["domainId"] = dnsResp.Domain.Id
|
this.Data["domainId"] = dnsInfoResp.Domain.Id
|
||||||
this.Data["domain"] = dnsResp.Domain.Name
|
this.Data["domain"] = dnsInfoResp.Domain.Name
|
||||||
} else {
|
} else {
|
||||||
this.Data["domainId"] = 0
|
this.Data["domainId"] = 0
|
||||||
this.Data["domain"] = ""
|
this.Data["domain"] = ""
|
||||||
}
|
}
|
||||||
if dnsResp.Provider != nil {
|
if dnsInfoResp.Provider != nil {
|
||||||
this.Data["providerType"] = dnsResp.Provider.Type
|
this.Data["providerType"] = dnsInfoResp.Provider.Type
|
||||||
this.Data["providerId"] = dnsResp.Provider.Id
|
this.Data["providerId"] = dnsInfoResp.Provider.Id
|
||||||
} else {
|
} else {
|
||||||
this.Data["providerType"] = ""
|
this.Data["providerType"] = ""
|
||||||
this.Data["providerId"] = 0
|
this.Data["providerId"] = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dnsResp.CnameRecords) == 0 {
|
if len(dnsInfoResp.CnameRecords) == 0 {
|
||||||
this.Data["cnameRecords"] = []string{}
|
this.Data["cnameRecords"] = []string{}
|
||||||
} else {
|
} else {
|
||||||
this.Data["cnameRecords"] = dnsResp.CnameRecords
|
this.Data["cnameRecords"] = dnsInfoResp.CnameRecords
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Data["ttl"] = dnsResp.Ttl
|
this.Data["ttl"] = dnsInfoResp.Ttl
|
||||||
|
this.Data["cnameAsDomain"] = dnsInfoResp.CnameAsDomain
|
||||||
|
this.Data["includingLnNodes"] = dnsInfoResp.IncludingLnNodes
|
||||||
|
|
||||||
// 所有服务商
|
// 所有服务商
|
||||||
providerTypesResp, err := this.RPC().DNSProviderRPC().FindAllDNSProviderTypes(this.AdminContext(), &pb.FindAllDNSProviderTypesRequest{})
|
providerTypesResp, err := this.RPC().DNSProviderRPC().FindAllDNSProviderTypes(this.AdminContext(), &pb.FindAllDNSProviderTypesRequest{})
|
||||||
@@ -73,13 +75,15 @@ func (this *UpdateClusterPopupAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *UpdateClusterPopupAction) RunPost(params struct {
|
func (this *UpdateClusterPopupAction) RunPost(params struct {
|
||||||
ClusterId int64
|
ClusterId int64
|
||||||
DnsName string
|
DnsName string
|
||||||
DomainId int64
|
DomainId int64
|
||||||
NodesAutoSync bool
|
NodesAutoSync bool
|
||||||
ServersAutoSync bool
|
ServersAutoSync bool
|
||||||
CnameRecords []string
|
CnameRecords []string
|
||||||
Ttl int32
|
Ttl int32
|
||||||
|
CnameAsDomain bool
|
||||||
|
IncludingLnNodes bool
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
CSRF *actionutils.CSRF
|
||||||
@@ -108,13 +112,15 @@ func (this *UpdateClusterPopupAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterDNS(this.AdminContext(), &pb.UpdateNodeClusterDNSRequest{
|
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterDNS(this.AdminContext(), &pb.UpdateNodeClusterDNSRequest{
|
||||||
NodeClusterId: params.ClusterId,
|
NodeClusterId: params.ClusterId,
|
||||||
DnsName: params.DnsName,
|
DnsName: params.DnsName,
|
||||||
DnsDomainId: params.DomainId,
|
DnsDomainId: params.DomainId,
|
||||||
NodesAutoSync: params.NodesAutoSync,
|
NodesAutoSync: params.NodesAutoSync,
|
||||||
ServersAutoSync: params.ServersAutoSync,
|
ServersAutoSync: params.ServersAutoSync,
|
||||||
CnameRecords: params.CnameRecords,
|
CnameRecords: params.CnameRecords,
|
||||||
Ttl: params.Ttl,
|
Ttl: params.Ttl,
|
||||||
|
CnameAsDomain: params.CnameAsDomain,
|
||||||
|
IncludingLnNodes: params.IncludingLnNodes,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
this.Data["isUser"] = false
|
this.Data["isUser"] = false
|
||||||
this.Data["menu"] = "signIn"
|
this.Data["menu"] = "signIn"
|
||||||
|
|
||||||
timestamp := fmt.Sprintf("%d", time.Now().Unix())
|
var timestamp = fmt.Sprintf("%d", time.Now().Unix())
|
||||||
this.Data["token"] = stringutil.Md5(TokenSalt+timestamp) + timestamp
|
this.Data["token"] = stringutil.Md5(TokenSalt+timestamp) + timestamp
|
||||||
this.Data["from"] = params.From
|
this.Data["from"] = params.From
|
||||||
|
|
||||||
@@ -111,11 +111,11 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
if len(params.Token) <= 32 {
|
if len(params.Token) <= 32 {
|
||||||
this.Fail("请通过登录页面登录")
|
this.Fail("请通过登录页面登录")
|
||||||
}
|
}
|
||||||
timestampString := params.Token[32:]
|
var timestampString = params.Token[32:]
|
||||||
if stringutil.Md5(TokenSalt+timestampString) != params.Token[:32] {
|
if stringutil.Md5(TokenSalt+timestampString) != params.Token[:32] {
|
||||||
this.FailField("refresh", "登录页面已过期,请刷新后重试")
|
this.FailField("refresh", "登录页面已过期,请刷新后重试")
|
||||||
}
|
}
|
||||||
timestamp := types.Int64(timestampString)
|
var timestamp = types.Int64(timestampString)
|
||||||
if timestamp < time.Now().Unix()-1800 {
|
if timestamp < time.Now().Unix()-1800 {
|
||||||
this.FailField("refresh", "登录页面已过期,请刷新后重试")
|
this.FailField("refresh", "登录页面已过期,请刷新后重试")
|
||||||
}
|
}
|
||||||
@@ -157,7 +157,7 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if otpLoginResp.Login != nil && otpLoginResp.Login.IsOn {
|
if otpLoginResp.Login != nil && otpLoginResp.Login.IsOn {
|
||||||
loginParams := maps.Map{}
|
var loginParams = maps.Map{}
|
||||||
err = json.Unmarshal(otpLoginResp.Login.ParamsJSON, &loginParams)
|
err = json.Unmarshal(otpLoginResp.Login.ParamsJSON, &loginParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
@@ -169,7 +169,7 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
adminId := resp.AdminId
|
var adminId = resp.AdminId
|
||||||
params.Auth.StoreAdmin(adminId, params.Remember)
|
params.Auth.StoreAdmin(adminId, params.Remember)
|
||||||
|
|
||||||
// 记录日志
|
// 记录日志
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/lists"
|
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
"github.com/tealeg/xlsx/v3"
|
"github.com/tealeg/xlsx/v3"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -69,17 +68,13 @@ func (this *ExportExcelAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if regionResp.IpRegion != nil {
|
if regionResp.IpRegion != nil {
|
||||||
pieces := []string{}
|
regionName = regionResp.IpRegion.Summary
|
||||||
if len(regionResp.IpRegion.Country) > 0 {
|
|
||||||
pieces = append(pieces, regionResp.IpRegion.Country)
|
// remove isp from regionName
|
||||||
|
var index = strings.LastIndex(regionName, "|")
|
||||||
|
if index > 0 {
|
||||||
|
regionName = regionName[:index]
|
||||||
}
|
}
|
||||||
if len(regionResp.IpRegion.Province) > 0 && !lists.ContainsString(pieces, regionResp.IpRegion.Province) {
|
|
||||||
pieces = append(pieces, regionResp.IpRegion.Province)
|
|
||||||
}
|
|
||||||
if len(regionResp.IpRegion.City) > 0 && !lists.ContainsString(pieces, regionResp.IpRegion.City) && !lists.ContainsString(pieces, strings.TrimSuffix(regionResp.IpRegion.Province, "市")) {
|
|
||||||
pieces = append(pieces, regionResp.IpRegion.City)
|
|
||||||
}
|
|
||||||
regionName = strings.Join(pieces, " ")
|
|
||||||
|
|
||||||
if len(regionResp.IpRegion.Isp) > 0 {
|
if len(regionResp.IpRegion.Isp) > 0 {
|
||||||
ispName = regionResp.IpRegion.Isp
|
ispName = regionResp.IpRegion.Isp
|
||||||
|
|||||||
@@ -4,10 +4,8 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/lists"
|
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexAction struct {
|
type IndexAction struct {
|
||||||
@@ -72,11 +70,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if regionResp.IpRegion != nil {
|
if regionResp.IpRegion != nil {
|
||||||
pieces := []string{regionResp.IpRegion.Summary}
|
regionName = regionResp.IpRegion.Summary
|
||||||
if len(regionResp.IpRegion.Isp) > 0 && !lists.ContainsString(pieces, regionResp.IpRegion.Isp) {
|
|
||||||
pieces = append(pieces, "| "+regionResp.IpRegion.Isp)
|
|
||||||
}
|
|
||||||
regionName = strings.Join(pieces, " ")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logMaps = append(logMaps, maps.Map{
|
logMaps = append(logMaps, maps.Map{
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
this.NotFound("firewallPolicy", params.FirewallPolicyId)
|
this.NotFound("firewallPolicy", params.FirewallPolicyId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
selectedCountryIds := []int64{}
|
var selectedCountryIds = []int64{}
|
||||||
if policyConfig.Inbound != nil && policyConfig.Inbound.Region != nil {
|
if policyConfig.Inbound != nil && policyConfig.Inbound.Region != nil {
|
||||||
selectedCountryIds = policyConfig.Inbound.Region.DenyCountryIds
|
selectedCountryIds = policyConfig.Inbound.Region.DenyCountryIds
|
||||||
}
|
}
|
||||||
@@ -46,11 +46,11 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
countryMaps := []maps.Map{}
|
var countryMaps = []maps.Map{}
|
||||||
for _, country := range countriesResp.RegionCountries {
|
for _, country := range countriesResp.RegionCountries {
|
||||||
countryMaps = append(countryMaps, maps.Map{
|
countryMaps = append(countryMaps, maps.Map{
|
||||||
"id": country.Id,
|
"id": country.Id,
|
||||||
"name": country.Name,
|
"name": country.DisplayName,
|
||||||
"letter": strings.ToUpper(string(country.Pinyin[0][0])),
|
"letter": strings.ToUpper(string(country.Pinyin[0][0])),
|
||||||
"isChecked": lists.ContainsInt64(selectedCountryIds, country.Id),
|
"isChecked": lists.ContainsInt64(selectedCountryIds, country.Id),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ func (this *ProvincesAction) RunGet(params struct {
|
|||||||
this.NotFound("firewallPolicy", params.FirewallPolicyId)
|
this.NotFound("firewallPolicy", params.FirewallPolicyId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
selectedProvinceIds := []int64{}
|
var selectedProvinceIds = []int64{}
|
||||||
if policyConfig.Inbound != nil && policyConfig.Inbound.Region != nil {
|
if policyConfig.Inbound != nil && policyConfig.Inbound.Region != nil {
|
||||||
selectedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
|
selectedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
|
||||||
}
|
}
|
||||||
@@ -49,11 +49,11 @@ func (this *ProvincesAction) RunGet(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
provinceMaps := []maps.Map{}
|
var provinceMaps = []maps.Map{}
|
||||||
for _, province := range provincesResp.RegionProvinces {
|
for _, province := range provincesResp.RegionProvinces {
|
||||||
provinceMaps = append(provinceMaps, maps.Map{
|
provinceMaps = append(provinceMaps, maps.Map{
|
||||||
"id": province.Id,
|
"id": province.Id,
|
||||||
"name": province.Name,
|
"name": province.DisplayName,
|
||||||
"isChecked": lists.ContainsInt64(selectedProvinceIds, province.Id),
|
"isChecked": lists.ContainsInt64(selectedProvinceIds, province.Id),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func (this *CountriesAction) RunGet(params struct {
|
|||||||
for _, country := range countriesResp.RegionCountries {
|
for _, country := range countriesResp.RegionCountries {
|
||||||
countryMaps = append(countryMaps, maps.Map{
|
countryMaps = append(countryMaps, maps.Map{
|
||||||
"id": country.Id,
|
"id": country.Id,
|
||||||
"name": country.Name,
|
"name": country.DisplayName,
|
||||||
"letter": strings.ToUpper(string(country.Pinyin[0][0])),
|
"letter": strings.ToUpper(string(country.Pinyin[0][0])),
|
||||||
"isChecked": lists.ContainsInt64(selectedCountryIds, country.Id),
|
"isChecked": lists.ContainsInt64(selectedCountryIds, country.Id),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ func (this *ProvincesAction) RunGet(params struct {
|
|||||||
selectedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
|
selectedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
|
||||||
}
|
}
|
||||||
|
|
||||||
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithCountryIdRequest{
|
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithRegionCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithRegionCountryIdRequest{
|
||||||
RegionCountryId: int64(ChinaCountryId),
|
RegionCountryId: int64(ChinaCountryId),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -57,7 +57,7 @@ func (this *ProvincesAction) RunGet(params struct {
|
|||||||
for _, province := range provincesResp.RegionProvinces {
|
for _, province := range provincesResp.RegionProvinces {
|
||||||
provinceMaps = append(provinceMaps, maps.Map{
|
provinceMaps = append(provinceMaps, maps.Map{
|
||||||
"id": province.Id,
|
"id": province.Id,
|
||||||
"name": province.Name,
|
"name": province.DisplayName,
|
||||||
"isChecked": lists.ContainsInt64(selectedProvinceIds, province.Id),
|
"isChecked": lists.ContainsInt64(selectedProvinceIds, province.Id),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,11 +217,8 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
|
|
||||||
// 统计数据
|
// 统计数据
|
||||||
var bandwidth = ""
|
var bandwidth = ""
|
||||||
if server.LatestServerDailyStat != nil {
|
if server.BandwidthBytes > 0 {
|
||||||
var bytesPerSecond = server.LatestServerDailyStat.Bytes / 300
|
bandwidth = numberutils.FormatBytes(server.BandwidthBytes)
|
||||||
if bytesPerSecond > 0 {
|
|
||||||
bandwidth = numberutils.FormatBytes(bytesPerSecond)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serverMaps = append(serverMaps, maps.Map{
|
serverMaps = append(serverMaps, maps.Map{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,7 +31,14 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if regionResp.IpRegion != nil {
|
if regionResp.IpRegion != nil {
|
||||||
this.Data["regions"] = regionResp.IpRegion.Summary
|
var regionName = regionResp.IpRegion.Summary
|
||||||
|
|
||||||
|
// remove isp from regionName
|
||||||
|
var index = strings.LastIndex(regionName, "|")
|
||||||
|
if index > 0 {
|
||||||
|
regionName = regionName[:index]
|
||||||
|
}
|
||||||
|
this.Data["regions"] = regionName
|
||||||
} else {
|
} else {
|
||||||
this.Data["regions"] = ""
|
this.Data["regions"] = ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package iplists
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,5 +24,8 @@ func (this *DeleteAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通知左侧菜单Badge更新
|
||||||
|
helpers.NotifyIPItemsCountChanges()
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package iplists
|
|||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -22,5 +23,8 @@ func (this *DeleteIPAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通知左侧菜单Badge更新
|
||||||
|
helpers.NotifyIPItemsCountChanges()
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package iplists
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -33,5 +34,8 @@ func (this *DeleteItemsAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通知左侧菜单Badge更新
|
||||||
|
helpers.NotifyIPItemsCountChanges()
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -165,6 +166,13 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
var ipRegion = regionResp.IpRegion
|
var ipRegion = regionResp.IpRegion
|
||||||
if ipRegion != nil {
|
if ipRegion != nil {
|
||||||
region = ipRegion.Summary
|
region = ipRegion.Summary
|
||||||
|
|
||||||
|
// remove isp from regionName
|
||||||
|
var index = strings.LastIndex(region, "|")
|
||||||
|
if index > 0 {
|
||||||
|
region = region[:index]
|
||||||
|
}
|
||||||
|
|
||||||
isp = ipRegion.Isp
|
isp = ipRegion.Isp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -116,6 +117,13 @@ func (this *ItemsAction) RunGet(params struct {
|
|||||||
var ipRegion = regionResp.IpRegion
|
var ipRegion = regionResp.IpRegion
|
||||||
if ipRegion != nil {
|
if ipRegion != nil {
|
||||||
region = ipRegion.Summary
|
region = ipRegion.Summary
|
||||||
|
|
||||||
|
// remove isp from regionName
|
||||||
|
var index = strings.LastIndex(region, "|")
|
||||||
|
if index > 0 {
|
||||||
|
region = region[:index]
|
||||||
|
}
|
||||||
|
|
||||||
isp = ipRegion.Isp
|
isp = ipRegion.Isp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package iplists
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,5 +21,8 @@ func (this *ReadAllAction) RunPost(params struct{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通知左侧菜单Badge更新
|
||||||
|
helpers.NotifyIPItemsCountChanges()
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
67
internal/web/actions/default/servers/logs/hasLogs.go
Normal file
67
internal/web/actions/default/servers/logs/hasLogs.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package logs
|
||||||
|
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HasLogsAction 检查某个分区是否有日志
|
||||||
|
type HasLogsAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *HasLogsAction) RunPost(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
NodeId int64
|
||||||
|
Day string
|
||||||
|
Hour string
|
||||||
|
Keyword string
|
||||||
|
Ip string
|
||||||
|
Domain string
|
||||||
|
HasError int
|
||||||
|
HasWAF int
|
||||||
|
Partition int32 `default:"-1"`
|
||||||
|
|
||||||
|
RequestId string
|
||||||
|
ServerId int64
|
||||||
|
}) {
|
||||||
|
if len(params.Day) == 0 {
|
||||||
|
params.Day = timeutil.Format("Y-m-d")
|
||||||
|
}
|
||||||
|
|
||||||
|
var day = params.Day
|
||||||
|
|
||||||
|
if len(day) > 0 && regexp.MustCompile(`\d{4}-\d{2}-\d{2}`).MatchString(day) {
|
||||||
|
day = strings.ReplaceAll(day, "-", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
|
||||||
|
Partition: params.Partition,
|
||||||
|
RequestId: params.RequestId,
|
||||||
|
NodeClusterId: params.ClusterId,
|
||||||
|
NodeId: params.NodeId,
|
||||||
|
ServerId: params.ServerId,
|
||||||
|
HasError: params.HasError > 0,
|
||||||
|
HasFirewallPolicy: params.HasWAF > 0,
|
||||||
|
Day: day,
|
||||||
|
HourFrom: params.Hour,
|
||||||
|
HourTo: params.Hour,
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
Ip: params.Ip,
|
||||||
|
Domain: params.Domain,
|
||||||
|
Size: 1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["hasLogs"] = len(resp.HttpAccessLogs) > 0
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ func init() {
|
|||||||
Get("", new(IndexAction)).
|
Get("", new(IndexAction)).
|
||||||
GetPost("/settings", new(SettingsAction)).
|
GetPost("/settings", new(SettingsAction)).
|
||||||
Post("/partitionData", new(PartitionDataAction)).
|
Post("/partitionData", new(PartitionDataAction)).
|
||||||
|
Post("/hasLogs", new(HasLogsAction)).
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,8 +93,16 @@ func (this *ViewPopupAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
region := regionResp.IpRegion
|
region := regionResp.IpRegion
|
||||||
if region != nil {
|
if region != nil {
|
||||||
|
var regionName = region.Summary
|
||||||
|
|
||||||
|
// remove isp from regionName
|
||||||
|
var index = strings.LastIndex(regionName, "|")
|
||||||
|
if index > 0 {
|
||||||
|
regionName = regionName[:index]
|
||||||
|
}
|
||||||
|
|
||||||
regionMap = maps.Map{
|
regionMap = maps.Map{
|
||||||
"full": region.Summary,
|
"full": regionName,
|
||||||
"isp": region.Isp,
|
"isp": region.Isp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
//go:build !plus
|
||||||
|
|
||||||
package access
|
package access
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CreatePopupAction struct {
|
type CreatePopupAction struct {
|
||||||
@@ -37,6 +40,9 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
SubRequestMethod string
|
SubRequestMethod string
|
||||||
SubRequestFollowRequest bool
|
SubRequestFollowRequest bool
|
||||||
|
|
||||||
|
Exts []string
|
||||||
|
DomainsJSON []byte
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
CSRF *actionutils.CSRF
|
||||||
}) {
|
}) {
|
||||||
@@ -44,14 +50,42 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
Field("name", params.Name).
|
Field("name", params.Name).
|
||||||
Require("请输入名称").
|
Require("请输入名称").
|
||||||
Field("type", params.Type).
|
Field("type", params.Type).
|
||||||
Require("请输入认证类型")
|
Require("请输入鉴权类型")
|
||||||
|
|
||||||
var ref = &serverconfigs.HTTPAuthPolicyRef{IsOn: true}
|
var ref = &serverconfigs.HTTPAuthPolicyRef{IsOn: true}
|
||||||
var paramsJSON []byte
|
|
||||||
|
// 扩展名
|
||||||
|
var exts = utils.NewStringsStream(params.Exts).
|
||||||
|
Map(strings.TrimSpace, strings.ToLower).
|
||||||
|
Filter(utils.FilterNotEmpty).
|
||||||
|
Map(utils.MapAddPrefixFunc(".")).
|
||||||
|
Unique().
|
||||||
|
Result()
|
||||||
|
|
||||||
|
// 域名
|
||||||
|
var domains = []string{}
|
||||||
|
if len(params.DomainsJSON) > 0 {
|
||||||
|
var rawDomains = []string{}
|
||||||
|
err := json.Unmarshal(params.DomainsJSON, &rawDomains)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO 如果用户填写了一个网址,应该分析域名并填入
|
||||||
|
|
||||||
|
domains = utils.NewStringsStream(rawDomains).
|
||||||
|
Map(strings.TrimSpace, strings.ToLower).
|
||||||
|
Filter(utils.FilterNotEmpty).
|
||||||
|
Unique().
|
||||||
|
Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
var method serverconfigs.HTTPAuthMethodInterface
|
||||||
|
|
||||||
switch params.Type {
|
switch params.Type {
|
||||||
case serverconfigs.HTTPAuthTypeBasicAuth:
|
case serverconfigs.HTTPAuthTypeBasicAuth:
|
||||||
users := []*serverconfigs.HTTPAuthBasicMethodUser{}
|
var users = []*serverconfigs.HTTPAuthBasicMethodUser{}
|
||||||
err := json.Unmarshal(params.HttpAuthBasicAuthUsersJSON, &users)
|
err := json.Unmarshal(params.HttpAuthBasicAuthUsersJSON, &users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
@@ -60,40 +94,39 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
if len(users) == 0 {
|
if len(users) == 0 {
|
||||||
this.Fail("请添加至少一个用户")
|
this.Fail("请添加至少一个用户")
|
||||||
}
|
}
|
||||||
method := &serverconfigs.HTTPAuthBasicMethod{
|
method = &serverconfigs.HTTPAuthBasicMethod{
|
||||||
Users: users,
|
Users: users,
|
||||||
Realm: params.BasicAuthRealm,
|
Realm: params.BasicAuthRealm,
|
||||||
Charset: params.BasicAuthCharset,
|
Charset: params.BasicAuthCharset,
|
||||||
}
|
}
|
||||||
methodJSON, err := json.Marshal(method)
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
paramsJSON = methodJSON
|
|
||||||
case serverconfigs.HTTPAuthTypeSubRequest:
|
case serverconfigs.HTTPAuthTypeSubRequest:
|
||||||
params.Must.Field("subRequestURL", params.SubRequestURL).
|
params.Must.Field("subRequestURL", params.SubRequestURL).
|
||||||
Require("请输入子请求URL")
|
Require("请输入子请求URL")
|
||||||
if params.SubRequestFollowRequest {
|
if params.SubRequestFollowRequest {
|
||||||
params.SubRequestMethod = ""
|
params.SubRequestMethod = ""
|
||||||
}
|
}
|
||||||
method := &serverconfigs.HTTPAuthSubRequestMethod{
|
method = &serverconfigs.HTTPAuthSubRequestMethod{
|
||||||
URL: params.SubRequestURL,
|
URL: params.SubRequestURL,
|
||||||
Method: params.SubRequestMethod,
|
Method: params.SubRequestMethod,
|
||||||
}
|
}
|
||||||
methodJSON, err := json.Marshal(method)
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
paramsJSON = methodJSON
|
|
||||||
default:
|
default:
|
||||||
this.Fail("不支持的认证类型'" + params.Type + "'")
|
this.Fail("不支持的鉴权类型'" + params.Type + "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
if method == nil {
|
||||||
|
this.Fail("无法找到对应的鉴权方式")
|
||||||
|
}
|
||||||
|
method.SetExts(exts)
|
||||||
|
method.SetDomains(domains)
|
||||||
|
|
||||||
|
paramsJSON, err := json.Marshal(method)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var paramsMap map[string]interface{}
|
var paramsMap map[string]interface{}
|
||||||
err := json.Unmarshal(paramsJSON, ¶msMap)
|
err = json.Unmarshal(paramsJSON, ¶msMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
@@ -108,7 +141,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer this.CreateLogInfo("创建HTTP认证 %d", createResp.HttpAuthPolicyId)
|
defer this.CreateLogInfo("创建HTTP鉴权 %d", createResp.HttpAuthPolicyId)
|
||||||
ref.AuthPolicyId = createResp.HttpAuthPolicyId
|
ref.AuthPolicyId = createResp.HttpAuthPolicyId
|
||||||
ref.AuthPolicy = &serverconfigs.HTTPAuthPolicy{
|
ref.AuthPolicy = &serverconfigs.HTTPAuthPolicy{
|
||||||
Id: createResp.HttpAuthPolicyId,
|
Id: createResp.HttpAuthPolicyId,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexAction struct {
|
type IndexAction struct {
|
||||||
@@ -28,6 +29,28 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.Data["webId"] = webConfig.Id
|
this.Data["webId"] = webConfig.Id
|
||||||
|
|
||||||
|
// 移除不存在的鉴权方法
|
||||||
|
var allTypes = []string{}
|
||||||
|
for _, def := range serverconfigs.FindAllHTTPAuthTypes() {
|
||||||
|
allTypes = append(allTypes, def.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
if webConfig.Auth != nil {
|
||||||
|
var refs = webConfig.Auth.PolicyRefs
|
||||||
|
var realRefs = []*serverconfigs.HTTPAuthPolicyRef{}
|
||||||
|
for _, ref := range refs {
|
||||||
|
if ref.AuthPolicy == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !lists.ContainsString(allTypes, ref.AuthPolicy.Type) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
realRefs = append(realRefs, ref)
|
||||||
|
}
|
||||||
|
webConfig.Auth.PolicyRefs = realRefs
|
||||||
|
}
|
||||||
|
|
||||||
this.Data["authConfig"] = webConfig.Auth
|
this.Data["authConfig"] = webConfig.Auth
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
@@ -38,9 +61,8 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
AuthJSON []byte
|
AuthJSON []byte
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
|
||||||
}) {
|
}) {
|
||||||
defer this.CreateLogInfo("修改Web %d 的认证设置", params.WebId)
|
defer this.CreateLogInfo("修改Web %d 的鉴权设置", params.WebId)
|
||||||
|
|
||||||
var authConfig = &serverconfigs.HTTPAuthConfig{}
|
var authConfig = &serverconfigs.HTTPAuthConfig{}
|
||||||
err := json.Unmarshal(params.AuthJSON, authConfig)
|
err := json.Unmarshal(params.AuthJSON, authConfig)
|
||||||
@@ -53,7 +75,7 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
this.Fail("配置校验失败:" + err.Error())
|
this.Fail("配置校验失败:" + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存之前删除多于的配置信息
|
// 保存之前删除多余的配置信息
|
||||||
for _, ref := range authConfig.PolicyRefs {
|
for _, ref := range authConfig.PolicyRefs {
|
||||||
ref.AuthPolicy = nil
|
ref.AuthPolicy = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ func init() {
|
|||||||
GetPost("", new(IndexAction)).
|
GetPost("", new(IndexAction)).
|
||||||
GetPost("/createPopup", new(CreatePopupAction)).
|
GetPost("/createPopup", new(CreatePopupAction)).
|
||||||
GetPost("/updatePopup", new(UpdatePopupAction)).
|
GetPost("/updatePopup", new(UpdatePopupAction)).
|
||||||
|
Post("/random", new(RandomAction)).
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package access
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/iwind/TeaGo/rands"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RandomAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *RandomAction) RunPost(params struct{}) {
|
||||||
|
this.Data["random"] = rands.HexString(32)
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -1,14 +1,17 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
//go:build !plus
|
||||||
|
|
||||||
package access
|
package access
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UpdatePopupAction struct {
|
type UpdatePopupAction struct {
|
||||||
@@ -70,17 +73,20 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
|||||||
SubRequestMethod string
|
SubRequestMethod string
|
||||||
SubRequestFollowRequest bool
|
SubRequestFollowRequest bool
|
||||||
|
|
||||||
|
Exts []string
|
||||||
|
DomainsJSON []byte
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
CSRF *actionutils.CSRF
|
||||||
}) {
|
}) {
|
||||||
defer this.CreateLogInfo("修改HTTP认证 %d", params.PolicyId)
|
defer this.CreateLogInfo("修改HTTP鉴权 %d", params.PolicyId)
|
||||||
|
|
||||||
policyResp, err := this.RPC().HTTPAuthPolicyRPC().FindEnabledHTTPAuthPolicy(this.AdminContext(), &pb.FindEnabledHTTPAuthPolicyRequest{HttpAuthPolicyId: params.PolicyId})
|
policyResp, err := this.RPC().HTTPAuthPolicyRPC().FindEnabledHTTPAuthPolicy(this.AdminContext(), &pb.FindEnabledHTTPAuthPolicyRequest{HttpAuthPolicyId: params.PolicyId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
policy := policyResp.HttpAuthPolicy
|
var policy = policyResp.HttpAuthPolicy
|
||||||
if policy == nil {
|
if policy == nil {
|
||||||
this.NotFound("httpAuthPolicy", params.PolicyId)
|
this.NotFound("httpAuthPolicy", params.PolicyId)
|
||||||
return
|
return
|
||||||
@@ -91,12 +97,40 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
|||||||
Field("name", params.Name).
|
Field("name", params.Name).
|
||||||
Require("请输入名称")
|
Require("请输入名称")
|
||||||
|
|
||||||
|
// 扩展名
|
||||||
|
var exts = utils.NewStringsStream(params.Exts).
|
||||||
|
Map(strings.TrimSpace, strings.ToLower).
|
||||||
|
Filter(utils.FilterNotEmpty).
|
||||||
|
Map(utils.MapAddPrefixFunc(".")).
|
||||||
|
Unique().
|
||||||
|
Result()
|
||||||
|
|
||||||
|
// 域名
|
||||||
|
var domains = []string{}
|
||||||
|
if len(params.DomainsJSON) > 0 {
|
||||||
|
var rawDomains = []string{}
|
||||||
|
err := json.Unmarshal(params.DomainsJSON, &rawDomains)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO 如果用户填写了一个网址,应该分析域名并填入
|
||||||
|
|
||||||
|
domains = utils.NewStringsStream(rawDomains).
|
||||||
|
Map(strings.TrimSpace, strings.ToLower).
|
||||||
|
Filter(utils.FilterNotEmpty).
|
||||||
|
Unique().
|
||||||
|
Result()
|
||||||
|
}
|
||||||
|
|
||||||
var ref = &serverconfigs.HTTPAuthPolicyRef{IsOn: true}
|
var ref = &serverconfigs.HTTPAuthPolicyRef{IsOn: true}
|
||||||
var paramsJSON []byte
|
|
||||||
|
var method serverconfigs.HTTPAuthMethodInterface
|
||||||
|
|
||||||
switch policyType {
|
switch policyType {
|
||||||
case serverconfigs.HTTPAuthTypeBasicAuth:
|
case serverconfigs.HTTPAuthTypeBasicAuth:
|
||||||
users := []*serverconfigs.HTTPAuthBasicMethodUser{}
|
var users = []*serverconfigs.HTTPAuthBasicMethodUser{}
|
||||||
err := json.Unmarshal(params.HttpAuthBasicAuthUsersJSON, &users)
|
err := json.Unmarshal(params.HttpAuthBasicAuthUsersJSON, &users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
@@ -105,36 +139,35 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
|||||||
if len(users) == 0 {
|
if len(users) == 0 {
|
||||||
this.Fail("请添加至少一个用户")
|
this.Fail("请添加至少一个用户")
|
||||||
}
|
}
|
||||||
method := &serverconfigs.HTTPAuthBasicMethod{
|
method = &serverconfigs.HTTPAuthBasicMethod{
|
||||||
Users: users,
|
Users: users,
|
||||||
Realm: params.BasicAuthRealm,
|
Realm: params.BasicAuthRealm,
|
||||||
Charset: params.BasicAuthCharset,
|
Charset: params.BasicAuthCharset,
|
||||||
}
|
}
|
||||||
methodJSON, err := json.Marshal(method)
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
paramsJSON = methodJSON
|
|
||||||
case serverconfigs.HTTPAuthTypeSubRequest:
|
case serverconfigs.HTTPAuthTypeSubRequest:
|
||||||
params.Must.Field("subRequestURL", params.SubRequestURL).
|
params.Must.Field("subRequestURL", params.SubRequestURL).
|
||||||
Require("请输入子请求URL")
|
Require("请输入子请求URL")
|
||||||
if params.SubRequestFollowRequest {
|
if params.SubRequestFollowRequest {
|
||||||
params.SubRequestMethod = ""
|
params.SubRequestMethod = ""
|
||||||
}
|
}
|
||||||
method := &serverconfigs.HTTPAuthSubRequestMethod{
|
method = &serverconfigs.HTTPAuthSubRequestMethod{
|
||||||
URL: params.SubRequestURL,
|
URL: params.SubRequestURL,
|
||||||
Method: params.SubRequestMethod,
|
Method: params.SubRequestMethod,
|
||||||
}
|
}
|
||||||
methodJSON, err := json.Marshal(method)
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
paramsJSON = methodJSON
|
|
||||||
default:
|
default:
|
||||||
this.Fail("不支持的认证类型'" + policyType + "'")
|
this.Fail("不支持的鉴权类型'" + policyType + "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
if method == nil {
|
||||||
|
this.Fail("无法找到对应的鉴权方式")
|
||||||
|
}
|
||||||
|
method.SetExts(exts)
|
||||||
|
method.SetDomains(domains)
|
||||||
|
|
||||||
|
paramsJSON, err := json.Marshal(method)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var paramsMap map[string]interface{}
|
var paramsMap map[string]interface{}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -27,19 +28,45 @@ func (this *CreatePopupAction) RunGet(params struct {
|
|||||||
func (this *CreatePopupAction) RunPost(params struct {
|
func (this *CreatePopupAction) RunPost(params struct {
|
||||||
CacheRefJSON []byte
|
CacheRefJSON []byte
|
||||||
|
|
||||||
|
CondType string
|
||||||
|
CondJSON []byte
|
||||||
|
CondIsCaseInsensitive bool
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
}) {
|
}) {
|
||||||
var cacheRef = &serverconfigs.HTTPCacheRef{}
|
var cacheRef = &serverconfigs.HTTPCacheRef{}
|
||||||
err := json.Unmarshal(params.CacheRefJSON, cacheRef)
|
err := json.Unmarshal(params.CacheRefJSON, cacheRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.Fail("解析条件出错:" + err.Error() + ", JSON: " + string(params.CacheRefJSON))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(params.CondJSON) > 0 {
|
||||||
|
var cond = &shared.HTTPRequestCond{}
|
||||||
|
err = json.Unmarshal(params.CondJSON, cond)
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("解析条件出错:" + err.Error() + ", JSON: " + string(params.CondJSON))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cond.Type = params.CondType
|
||||||
|
cond.IsCaseInsensitive = params.CondIsCaseInsensitive
|
||||||
|
cacheRef.SimpleCond = cond
|
||||||
|
|
||||||
|
// 将组合条件置为空
|
||||||
|
cacheRef.Conds = &shared.HTTPRequestCondsConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cacheRef.Init()
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("解析条件出错:" + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if len(cacheRef.Key) == 0 {
|
if len(cacheRef.Key) == 0 {
|
||||||
this.Fail("请输入缓存Key")
|
this.Fail("请输入缓存Key")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cacheRef.Conds == nil || len(cacheRef.Conds.Groups) == 0 {
|
if (cacheRef.Conds == nil || len(cacheRef.Conds.Groups) == 0) && cacheRef.SimpleCond == nil {
|
||||||
this.Fail("请填写匹配条件分组")
|
this.Fail("请填写匹配条件分组")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ func init() {
|
|||||||
Prefix("/servers/server/settings/dns").
|
Prefix("/servers/server/settings/dns").
|
||||||
GetPost("", new(IndexAction)).
|
GetPost("", new(IndexAction)).
|
||||||
Post("/regenerateCNAME", new(RegenerateCNAMEAction)).
|
Post("/regenerateCNAME", new(RegenerateCNAMEAction)).
|
||||||
|
GetPost("/updateCNAMEPopup", new(UpdateCNAMEPopupAction)).
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func (this *RegenerateCNAMEAction) RunPost(params struct {
|
|||||||
}) {
|
}) {
|
||||||
defer this.CreateLogInfo("重新生成服务 %d 的CNAME", params.ServerId)
|
defer this.CreateLogInfo("重新生成服务 %d 的CNAME", params.ServerId)
|
||||||
|
|
||||||
_, err := this.RPC().ServerRPC().RegenerateServerCNAME(this.AdminContext(), &pb.RegenerateServerCNAMERequest{ServerId: params.ServerId})
|
_, err := this.RPC().ServerRPC().RegenerateServerDNSName(this.AdminContext(), &pb.RegenerateServerDNSNameRequest{ServerId: params.ServerId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateCNAMEPopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateCNAMEPopupAction) RunGet(params struct {
|
||||||
|
ServerId int64
|
||||||
|
}) {
|
||||||
|
this.Data["serverId"] = params.ServerId
|
||||||
|
|
||||||
|
dnsInfoResp, err := this.RPC().ServerRPC().FindEnabledServerDNS(this.AdminContext(), &pb.FindEnabledServerDNSRequest{ServerId: params.ServerId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["dnsName"] = dnsInfoResp.DnsName
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateCNAMEPopupAction) RunPost(params struct {
|
||||||
|
ServerId int64
|
||||||
|
DnsName string
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("修改服务 %d CNAME为 %s", params.ServerId, params.DnsName)
|
||||||
|
|
||||||
|
var dnsName = strings.ToLower(params.DnsName)
|
||||||
|
if len(dnsName) == 0 {
|
||||||
|
this.FailField("dnsName", "CNAME不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxLen = 30
|
||||||
|
if len(dnsName) > maxLen {
|
||||||
|
this.FailField("dnsName", "CNAME长度不能超过"+types.String(maxLen)+"个字符")
|
||||||
|
}
|
||||||
|
if !regexp.MustCompile(`^[a-z0-9]{1,` + types.String(maxLen) + `}$`).MatchString(dnsName) {
|
||||||
|
this.FailField("dnsName", "CNAME中只能包含数字、英文字母")
|
||||||
|
}
|
||||||
|
|
||||||
|
serverResp, err := this.RPC().ServerRPC().FindEnabledServer(this.AdminContext(), &pb.FindEnabledServerRequest{ServerId: params.ServerId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var server = serverResp.Server
|
||||||
|
if server == nil {
|
||||||
|
this.Fail("找不到要修改的服务")
|
||||||
|
}
|
||||||
|
if server.NodeCluster == nil {
|
||||||
|
this.Fail("服务必须先分配到一个集群才能修改")
|
||||||
|
}
|
||||||
|
var clusterId = server.NodeCluster.Id
|
||||||
|
|
||||||
|
if server.DnsName == params.DnsName {
|
||||||
|
// 没有修改则直接返回
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
|
|
||||||
|
serverIdResp, err := this.RPC().ServerRPC().FindServerIdWithDNSName(this.AdminContext(), &pb.FindServerIdWithDNSNameRequest{
|
||||||
|
NodeClusterId: clusterId,
|
||||||
|
DnsName: dnsName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if serverIdResp.ServerId > 0 && serverIdResp.ServerId != params.ServerId {
|
||||||
|
this.FailField("dnsName", "当前CNAME已被别的服务占用,请换一个")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = this.RPC().ServerRPC().UpdateServerDNSName(this.AdminContext(), &pb.UpdateServerDNSNameRequest{
|
||||||
|
ServerId: params.ServerId,
|
||||||
|
DnsName: dnsName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexAction struct {
|
type IndexAction struct {
|
||||||
@@ -28,6 +29,28 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.Data["webId"] = webConfig.Id
|
this.Data["webId"] = webConfig.Id
|
||||||
|
|
||||||
|
// 移除不存在的鉴权方法
|
||||||
|
var allTypes = []string{}
|
||||||
|
for _, def := range serverconfigs.FindAllHTTPAuthTypes() {
|
||||||
|
allTypes = append(allTypes, def.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
if webConfig.Auth != nil {
|
||||||
|
var refs = webConfig.Auth.PolicyRefs
|
||||||
|
var realRefs = []*serverconfigs.HTTPAuthPolicyRef{}
|
||||||
|
for _, ref := range refs {
|
||||||
|
if ref.AuthPolicy == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !lists.ContainsString(allTypes, ref.AuthPolicy.Type) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
realRefs = append(realRefs, ref)
|
||||||
|
}
|
||||||
|
webConfig.Auth.PolicyRefs = realRefs
|
||||||
|
}
|
||||||
|
|
||||||
this.Data["authConfig"] = webConfig.Auth
|
this.Data["authConfig"] = webConfig.Auth
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
@@ -38,7 +61,6 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
AuthJSON []byte
|
AuthJSON []byte
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
|
||||||
}) {
|
}) {
|
||||||
defer this.CreateLogInfo("修改Web %d 的认证设置", params.WebId)
|
defer this.CreateLogInfo("修改Web %d 的认证设置", params.WebId)
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ func (this *LocationHelper) createMenus(serverIdString string, locationIdString
|
|||||||
"isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.Cache != nil && locationConfig.Web.Cache.IsPrior && locationConfig.Web.Cache.IsOn,
|
"isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.Cache != nil && locationConfig.Web.Cache.IsPrior && locationConfig.Web.Cache.IsOn,
|
||||||
})
|
})
|
||||||
menuItems = append(menuItems, maps.Map{
|
menuItems = append(menuItems, maps.Map{
|
||||||
"name": "访问控制",
|
"name": "访问鉴权",
|
||||||
"url": "/servers/server/settings/locations/access?serverId=" + serverIdString + "&locationId=" + locationIdString,
|
"url": "/servers/server/settings/locations/access?serverId=" + serverIdString + "&locationId=" + locationIdString,
|
||||||
"isActive": secondMenuItem == "access",
|
"isActive": secondMenuItem == "access",
|
||||||
"isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.Auth != nil && locationConfig.Web.Auth.IsPrior,
|
"isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.Auth != nil && locationConfig.Web.Auth.IsPrior,
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func (this *CountriesAction) RunGet(params struct {
|
|||||||
for _, country := range countriesResp.RegionCountries {
|
for _, country := range countriesResp.RegionCountries {
|
||||||
countryMaps = append(countryMaps, maps.Map{
|
countryMaps = append(countryMaps, maps.Map{
|
||||||
"id": country.Id,
|
"id": country.Id,
|
||||||
"name": country.Name,
|
"name": country.DisplayName,
|
||||||
"letter": strings.ToUpper(string(country.Pinyin[0][0])),
|
"letter": strings.ToUpper(string(country.Pinyin[0][0])),
|
||||||
"isChecked": lists.ContainsInt64(selectedCountryIds, country.Id),
|
"isChecked": lists.ContainsInt64(selectedCountryIds, country.Id),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ func (this *ProvincesAction) RunGet(params struct {
|
|||||||
for _, province := range provincesResp.RegionProvinces {
|
for _, province := range provincesResp.RegionProvinces {
|
||||||
provinceMaps = append(provinceMaps, maps.Map{
|
provinceMaps = append(provinceMaps, maps.Map{
|
||||||
"id": province.Id,
|
"id": province.Id,
|
||||||
"name": province.Name,
|
"name": province.DisplayName,
|
||||||
"isChecked": lists.ContainsInt64(selectedProvinceIds, province.Id),
|
"isChecked": lists.ContainsInt64(selectedProvinceIds, province.Id),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ func (this *ServerHelper) createSettingsMenu(secondMenuItem string, serverIdStri
|
|||||||
"isOn": serverConfig.Web != nil && serverConfig.Web.Cache != nil && serverConfig.Web.Cache.IsOn,
|
"isOn": serverConfig.Web != nil && serverConfig.Web.Cache != nil && serverConfig.Web.Cache.IsOn,
|
||||||
})
|
})
|
||||||
menuItems = append(menuItems, maps.Map{
|
menuItems = append(menuItems, maps.Map{
|
||||||
"name": "访问控制",
|
"name": "访问鉴权",
|
||||||
"url": "/servers/server/settings/access?serverId=" + serverIdString,
|
"url": "/servers/server/settings/access?serverId=" + serverIdString,
|
||||||
"isActive": secondMenuItem == "access",
|
"isActive": secondMenuItem == "access",
|
||||||
"isOn": serverConfig.Web != nil && serverConfig.Web.Auth != nil && serverConfig.Web.Auth.IsOn,
|
"isOn": serverConfig.Web != nil && serverConfig.Web.Auth != nil && serverConfig.Web.Auth.IsOn,
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
if country != nil {
|
if country != nil {
|
||||||
countryMaps = append(countryMaps, maps.Map{
|
countryMaps = append(countryMaps, maps.Map{
|
||||||
"id": country.Id,
|
"id": country.Id,
|
||||||
"name": country.Name,
|
"name": country.DisplayName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
if province != nil {
|
if province != nil {
|
||||||
provinceMaps = append(provinceMaps, maps.Map{
|
provinceMaps = append(provinceMaps, maps.Map{
|
||||||
"id": province.Id,
|
"id": province.Id,
|
||||||
"name": province.Name,
|
"name": province.DisplayName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ func (this *ProvinceOptionsAction) RunPost(params struct{}) {
|
|||||||
}
|
}
|
||||||
provinceMaps = append(provinceMaps, maps.Map{
|
provinceMaps = append(provinceMaps, maps.Map{
|
||||||
"id": province.Id,
|
"id": province.Id,
|
||||||
"name": province.Name,
|
"name": province.DisplayName,
|
||||||
"codes": province.Codes,
|
"codes": province.Codes,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func (this *SelectCountriesPopupAction) RunGet(params struct {
|
|||||||
for _, country := range countriesResp.RegionCountries {
|
for _, country := range countriesResp.RegionCountries {
|
||||||
countryMaps = append(countryMaps, maps.Map{
|
countryMaps = append(countryMaps, maps.Map{
|
||||||
"id": country.Id,
|
"id": country.Id,
|
||||||
"name": country.Name,
|
"name": country.DisplayName,
|
||||||
"letter": strings.ToUpper(string(country.Pinyin[0][0])),
|
"letter": strings.ToUpper(string(country.Pinyin[0][0])),
|
||||||
"isChecked": lists.ContainsInt64(selectedCountryIds, country.Id),
|
"isChecked": lists.ContainsInt64(selectedCountryIds, country.Id),
|
||||||
})
|
})
|
||||||
@@ -61,7 +61,7 @@ func (this *SelectCountriesPopupAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
countryMaps = append(countryMaps, maps.Map{
|
countryMaps = append(countryMaps, maps.Map{
|
||||||
"id": country.Id,
|
"id": country.Id,
|
||||||
"name": country.Name,
|
"name": country.DisplayName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.Data["countries"] = countryMaps
|
this.Data["countries"] = countryMaps
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func (this *SelectProvincesPopupAction) RunGet(params struct {
|
|||||||
for _, province := range provincesResp.RegionProvinces {
|
for _, province := range provincesResp.RegionProvinces {
|
||||||
provinceMaps = append(provinceMaps, maps.Map{
|
provinceMaps = append(provinceMaps, maps.Map{
|
||||||
"id": province.Id,
|
"id": province.Id,
|
||||||
"name": province.Name,
|
"name": province.DisplayName,
|
||||||
"isChecked": lists.ContainsInt64(selectedProvinceIds, province.Id),
|
"isChecked": lists.ContainsInt64(selectedProvinceIds, province.Id),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ func (this *SelectProvincesPopupAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
provinceMaps = append(provinceMaps, maps.Map{
|
provinceMaps = append(provinceMaps, maps.Map{
|
||||||
"id": province.Id,
|
"id": province.Id,
|
||||||
"name": province.Name,
|
"name": province.DisplayName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.Data["provinces"] = provinceMaps
|
this.Data["provinces"] = provinceMaps
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package users
|
package users
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"github.com/xlzd/gotp"
|
"github.com/xlzd/gotp"
|
||||||
@@ -22,15 +26,16 @@ func (this *CreatePopupAction) RunGet(params struct{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *CreatePopupAction) RunPost(params struct {
|
func (this *CreatePopupAction) RunPost(params struct {
|
||||||
Username string
|
Username string
|
||||||
Pass1 string
|
Pass1 string
|
||||||
Pass2 string
|
Pass2 string
|
||||||
Fullname string
|
Fullname string
|
||||||
Mobile string
|
Mobile string
|
||||||
Tel string
|
Tel string
|
||||||
Email string
|
Email string
|
||||||
Remark string
|
Remark string
|
||||||
ClusterId int64
|
ClusterId int64
|
||||||
|
FeaturesType string
|
||||||
|
|
||||||
// OTP
|
// OTP
|
||||||
OtpOn bool
|
OtpOn bool
|
||||||
@@ -38,6 +43,12 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
CSRF *actionutils.CSRF
|
||||||
}) {
|
}) {
|
||||||
|
var userId int64
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
this.CreateLogInfo("创建用户 %d", userId)
|
||||||
|
}()
|
||||||
|
|
||||||
params.Must.
|
params.Must.
|
||||||
Field("username", params.Username).
|
Field("username", params.Username).
|
||||||
Require("请输入用户名").
|
Require("请输入用户名").
|
||||||
@@ -97,9 +108,53 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var userId = createResp.UserId
|
userId = createResp.UserId
|
||||||
|
|
||||||
defer this.CreateLogInfo("创建用户 %d", userId)
|
// 功能
|
||||||
|
if teaconst.IsPlus {
|
||||||
|
if params.FeaturesType == "default" {
|
||||||
|
resp, err := this.RPC().SysSettingRPC().ReadSysSetting(this.AdminContext(), &pb.ReadSysSettingRequest{Code: systemconfigs.SettingCodeUserRegisterConfig})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = userconfigs.DefaultUserRegisterConfig()
|
||||||
|
if len(resp.ValueJSON) > 0 {
|
||||||
|
err = json.Unmarshal(resp.ValueJSON, config)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = this.RPC().UserRPC().UpdateUserFeatures(this.AdminContext(), &pb.UpdateUserFeaturesRequest{
|
||||||
|
UserId: userId,
|
||||||
|
FeatureCodes: config.Features,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if params.FeaturesType == "all" {
|
||||||
|
featuresResp, err := this.RPC().UserRPC().FindAllUserFeatureDefinitions(this.AdminContext(), &pb.FindAllUserFeatureDefinitionsRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var featureCodes = []string{}
|
||||||
|
for _, def := range featuresResp.Features {
|
||||||
|
featureCodes = append(featureCodes, def.Code)
|
||||||
|
}
|
||||||
|
_, err = this.RPC().UserRPC().UpdateUserFeatures(this.AdminContext(), &pb.UpdateUserFeaturesRequest{
|
||||||
|
UserId: userId,
|
||||||
|
FeatureCodes: featureCodes,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// OTP
|
// OTP
|
||||||
if params.OtpOn {
|
if params.OtpOn {
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ func init() {
|
|||||||
Prefix("/users").
|
Prefix("/users").
|
||||||
Get("", new(IndexAction)).
|
Get("", new(IndexAction)).
|
||||||
GetPost("/createPopup", new(CreatePopupAction)).
|
GetPost("/createPopup", new(CreatePopupAction)).
|
||||||
|
|
||||||
|
// 单个用户信息
|
||||||
Get("/user", new(UserAction)).
|
Get("/user", new(UserAction)).
|
||||||
GetPost("/update", new(UpdateAction)).
|
GetPost("/update", new(UpdateAction)).
|
||||||
Post("/delete", new(DeleteAction)).
|
Post("/delete", new(DeleteAction)).
|
||||||
@@ -28,6 +30,8 @@ func init() {
|
|||||||
GetPost("/createPopup", new(accesskeys.CreatePopupAction)).
|
GetPost("/createPopup", new(accesskeys.CreatePopupAction)).
|
||||||
Post("/delete", new(accesskeys.DeleteAction)).
|
Post("/delete", new(accesskeys.DeleteAction)).
|
||||||
Post("/updateIsOn", new(accesskeys.UpdateIsOnAction)).
|
Post("/updateIsOn", new(accesskeys.UpdateIsOnAction)).
|
||||||
|
|
||||||
|
//
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
1
internal/web/actions/default/users/user/.gitignore
vendored
Normal file
1
internal/web/actions/default/users/user/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
servers.go
|
||||||
@@ -22,6 +22,22 @@ import (
|
|||||||
var nodeLogsCountChanges = make(chan bool, 1)
|
var nodeLogsCountChanges = make(chan bool, 1)
|
||||||
var ipItemsCountChanges = make(chan bool, 1)
|
var ipItemsCountChanges = make(chan bool, 1)
|
||||||
|
|
||||||
|
func NotifyNodeLogsCountChange() {
|
||||||
|
select {
|
||||||
|
case nodeLogsCountChanges <- true:
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NotifyIPItemsCountChanges() {
|
||||||
|
select {
|
||||||
|
case ipItemsCountChanges <- true:
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 运行日志
|
// 运行日志
|
||||||
var countUnreadNodeLogs int64 = 0
|
var countUnreadNodeLogs int64 = 0
|
||||||
var nodeLogsType = ""
|
var nodeLogsType = ""
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
@@ -120,15 +121,20 @@ func checkRequestSecurity(securityConfig *systemconfigs.SecurityConfig, req *htt
|
|||||||
}
|
}
|
||||||
|
|
||||||
var userAgent = req.UserAgent()
|
var userAgent = req.UserAgent()
|
||||||
var referer = req.Referer()
|
var refererURL = req.Referer()
|
||||||
|
var referHost = ""
|
||||||
|
u, err := url.Parse(refererURL)
|
||||||
|
if err == nil {
|
||||||
|
referHost = u.Host
|
||||||
|
}
|
||||||
|
|
||||||
// 检查搜索引擎
|
// 检查搜索引擎
|
||||||
if securityConfig.DenySearchEngines && (len(userAgent) == 0 || searchEngineRegex.MatchString(userAgent) || (len(referer) > 0 && searchEngineRegex.MatchString(referer))) {
|
if securityConfig.DenySearchEngines && (len(userAgent) == 0 || searchEngineRegex.MatchString(userAgent) || (len(referHost) > 0 && searchEngineRegex.MatchString(referHost))) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查爬虫
|
// 检查爬虫
|
||||||
if securityConfig.DenySpiders && (len(userAgent) == 0 || spiderRegexp.MatchString(userAgent) || (len(referer) > 0 && spiderRegexp.MatchString(referer))) {
|
if securityConfig.DenySpiders && (len(userAgent) == 0 || spiderRegexp.MatchString(userAgent) || (len(referHost) > 0 && spiderRegexp.MatchString(referHost))) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,9 @@ Vue.component("node-ddos-protection-config-box", {
|
|||||||
maxConnections: 0,
|
maxConnections: 0,
|
||||||
maxConnectionsPerIP: 0,
|
maxConnectionsPerIP: 0,
|
||||||
newConnectionsRate: 0,
|
newConnectionsRate: 0,
|
||||||
|
newConnectionsRateBlockTimeout: 0,
|
||||||
|
newConnectionsSecondlyRate: 0,
|
||||||
|
newConnectionSecondlyRateBlockTimeout: 0,
|
||||||
allowIPList: [],
|
allowIPList: [],
|
||||||
ports: []
|
ports: []
|
||||||
}
|
}
|
||||||
@@ -24,6 +27,9 @@ Vue.component("node-ddos-protection-config-box", {
|
|||||||
maxConnections: 0,
|
maxConnections: 0,
|
||||||
maxConnectionsPerIP: 0,
|
maxConnectionsPerIP: 0,
|
||||||
newConnectionsRate: 0,
|
newConnectionsRate: 0,
|
||||||
|
newConnectionsRateBlockTimeout: 0,
|
||||||
|
newConnectionsSecondlyRate: 0,
|
||||||
|
newConnectionSecondlyRateBlockTimeout: 0,
|
||||||
allowIPList: [],
|
allowIPList: [],
|
||||||
ports: []
|
ports: []
|
||||||
}
|
}
|
||||||
@@ -80,13 +86,51 @@ Vue.component("node-ddos-protection-config-box", {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>单IP TCP新连接速率</td>
|
<td>单IP TCP新连接速率<em>(分钟)</em></td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui input right labeled">
|
<div class="ui fields inline">
|
||||||
<digit-input name="tcpNewConnectionsRate" v-model="config.tcp.newConnectionsRate" maxlength="6" size="6" style="width: 6em" :min="defaultConfigs.tcpNewConnectionsMinRate"></digit-input>
|
<div class="ui field">
|
||||||
<span class="ui label">个新连接/每分钟</span>
|
<div class="ui input right labeled">
|
||||||
|
<digit-input name="tcpNewConnectionsRate" v-model="config.tcp.newConnectionsRate" maxlength="6" size="6" style="width: 6em" :min="defaultConfigs.tcpNewConnectionsMinRate"></digit-input>
|
||||||
|
<span class="ui label">个新连接/每分钟</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui field" style="line-height: 2.4em">
|
||||||
|
屏蔽
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<div class="ui input right labeled">
|
||||||
|
<digit-input name="tcpNewConnectionsRateBlockTimeout" v-model="config.tcp.newConnectionsRateBlockTimeout" maxlength="6" size="6" style="width: 5em"></digit-input>
|
||||||
|
<span class="ui label">秒</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="comment">单个IP可以创建TCP新连接的速率。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinRate}}。</p>
|
|
||||||
|
<p class="comment">单个IP每分钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsMinutelyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinMinutelyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>单IP TCP新连接速率<em>(秒钟)</em></td>
|
||||||
|
<td>
|
||||||
|
<div class="ui fields inline">
|
||||||
|
<div class="ui field">
|
||||||
|
<div class="ui input right labeled">
|
||||||
|
<digit-input name="tcpNewConnectionsSecondlyRate" v-model="config.tcp.newConnectionsSecondlyRate" maxlength="6" size="6" style="width: 6em" :min="defaultConfigs.tcpNewConnectionsMinRate"></digit-input>
|
||||||
|
<span class="ui label">个新连接/每秒钟</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui field" style="line-height: 2.4em">
|
||||||
|
屏蔽
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<div class="ui input right labeled">
|
||||||
|
<digit-input name="tcpNewConnectionsSecondlyRateBlockTimeout" v-model="config.tcp.newConnectionsSecondlyRateBlockTimeout" maxlength="6" size="6" style="width: 5em"></digit-input>
|
||||||
|
<span class="ui label">秒</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="comment">单个IP每秒钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsSecondlyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinSecondlyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
3
web/public/js/components/common/dot.js
Normal file
3
web/public/js/components/common/dot.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Vue.component("dot", {
|
||||||
|
template: '<span style="display: inline-block; padding-bottom: 3px"><i class="icon circle tiny"></i></span>'
|
||||||
|
})
|
||||||
@@ -4,6 +4,7 @@ Vue.component("sort-arrow", {
|
|||||||
data: function () {
|
data: function () {
|
||||||
let url = window.location.toString()
|
let url = window.location.toString()
|
||||||
let order = ""
|
let order = ""
|
||||||
|
let iconTitle = ""
|
||||||
let newArgs = []
|
let newArgs = []
|
||||||
if (window.location.search != null && window.location.search.length > 0) {
|
if (window.location.search != null && window.location.search.length > 0) {
|
||||||
let queryString = window.location.search.substring(1)
|
let queryString = window.location.search.substring(1)
|
||||||
@@ -26,10 +27,13 @@ Vue.component("sort-arrow", {
|
|||||||
}
|
}
|
||||||
if (order == "asc") {
|
if (order == "asc") {
|
||||||
newArgs.push(this.name + "=desc")
|
newArgs.push(this.name + "=desc")
|
||||||
|
iconTitle = "当前正序排列"
|
||||||
} else if (order == "desc") {
|
} else if (order == "desc") {
|
||||||
newArgs.push(this.name + "=asc")
|
newArgs.push(this.name + "=asc")
|
||||||
|
iconTitle = "当前倒序排列"
|
||||||
} else {
|
} else {
|
||||||
newArgs.push(this.name + "=desc")
|
newArgs.push(this.name + "=desc")
|
||||||
|
iconTitle = "当前正序排列"
|
||||||
}
|
}
|
||||||
|
|
||||||
let qIndex = url.indexOf("?")
|
let qIndex = url.indexOf("?")
|
||||||
@@ -41,8 +45,9 @@ Vue.component("sort-arrow", {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
order: order,
|
order: order,
|
||||||
url: url
|
url: url,
|
||||||
|
iconTitle: iconTitle
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<a :href="url" title="排序"> <i class="ui icon long arrow small" :class="{down: order == 'asc', up: order == 'desc', 'down grey': order == '' || order == null}"></i></a>`
|
template: `<a :href="url" :title="iconTitle"> <i class="ui icon long arrow small" :class="{down: order == 'asc', up: order == 'desc', 'down grey': order == '' || order == null}"></i></a>`
|
||||||
})
|
})
|
||||||
@@ -68,6 +68,9 @@ Vue.component("values-box", {
|
|||||||
|
|
||||||
startEditing: function () {
|
startEditing: function () {
|
||||||
this.isEditing = !this.isEditing
|
this.isEditing = !this.isEditing
|
||||||
|
},
|
||||||
|
allValues: function () {
|
||||||
|
return this.realValues
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ Vue.component("node-level-selector", {
|
|||||||
levelCode: levelCode
|
levelCode: levelCode
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
levelCode: function (code) {
|
||||||
|
this.$emit("change", code)
|
||||||
|
}
|
||||||
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<select class="ui dropdown auto-width" name="level" v-model="levelCode">
|
<select class="ui dropdown auto-width" name="level" v-model="levelCode">
|
||||||
<option v-for="level in levels" :value="level.code">{{level.name}}</option>
|
<option v-for="level in levels" :value="level.code">{{level.name}}</option>
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
Vue.component("ns-node-ddos-protection-config-box", {
|
||||||
|
props: ["v-ddos-protection-config", "v-default-configs", "v-is-node", "v-cluster-is-on"],
|
||||||
|
data: function () {
|
||||||
|
let config = this.vDdosProtectionConfig
|
||||||
|
if (config == null) {
|
||||||
|
config = {
|
||||||
|
tcp: {
|
||||||
|
isPrior: false,
|
||||||
|
isOn: false,
|
||||||
|
maxConnections: 0,
|
||||||
|
maxConnectionsPerIP: 0,
|
||||||
|
newConnectionsRate: 0,
|
||||||
|
newConnectionsRateBlockTimeout: 0,
|
||||||
|
newConnectionsSecondlyRate: 0,
|
||||||
|
newConnectionSecondlyRateBlockTimeout: 0,
|
||||||
|
allowIPList: [],
|
||||||
|
ports: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize
|
||||||
|
if (config.tcp == null) {
|
||||||
|
config.tcp = {
|
||||||
|
isPrior: false,
|
||||||
|
isOn: false,
|
||||||
|
maxConnections: 0,
|
||||||
|
maxConnectionsPerIP: 0,
|
||||||
|
newConnectionsRate: 0,
|
||||||
|
newConnectionsRateBlockTimeout: 0,
|
||||||
|
newConnectionsSecondlyRate: 0,
|
||||||
|
newConnectionSecondlyRateBlockTimeout: 0,
|
||||||
|
allowIPList: [],
|
||||||
|
ports: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
config: config,
|
||||||
|
defaultConfigs: this.vDefaultConfigs,
|
||||||
|
isNode: this.vIsNode,
|
||||||
|
|
||||||
|
isAddingPort: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
changeTCPPorts: function (ports) {
|
||||||
|
this.config.tcp.ports = ports
|
||||||
|
},
|
||||||
|
changeTCPAllowIPList: function (ipList) {
|
||||||
|
this.config.tcp.allowIPList = ipList
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<input type="hidden" name="ddosProtectionJSON" :value="JSON.stringify(config)"/>
|
||||||
|
|
||||||
|
<p class="comment">功能说明:此功能为<strong>试验性质</strong>,目前仅能防御简单的DDoS攻击,试验期间建议仅在被攻击时启用,仅支持已安装<code-label>nftables v0.9</code-label>以上的Linux系统。<pro-warning-label></pro-warning-label></p>
|
||||||
|
|
||||||
|
<div class="ui message" v-if="vClusterIsOn">当前节点所在集群已设置DDoS防护。</div>
|
||||||
|
|
||||||
|
<h4>TCP设置</h4>
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<prior-checkbox :v-config="config.tcp" v-if="isNode"></prior-checkbox>
|
||||||
|
<tbody v-show="config.tcp.isPrior || !isNode">
|
||||||
|
<tr>
|
||||||
|
<td class="title">启用</td>
|
||||||
|
<td>
|
||||||
|
<checkbox v-model="config.tcp.isOn"></checkbox>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tbody v-show="config.tcp.isOn && (config.tcp.isPrior || !isNode)">
|
||||||
|
<tr>
|
||||||
|
<td class="title">单节点TCP最大连接数</td>
|
||||||
|
<td>
|
||||||
|
<digit-input name="tcpMaxConnections" v-model="config.tcp.maxConnections" maxlength="6" size="6" style="width: 6em"></digit-input>
|
||||||
|
<p class="comment">单个节点可以接受的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnections}}。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>单IP TCP最大连接数</td>
|
||||||
|
<td>
|
||||||
|
<digit-input name="tcpMaxConnectionsPerIP" v-model="config.tcp.maxConnectionsPerIP" maxlength="6" size="6" style="width: 6em"></digit-input>
|
||||||
|
<p class="comment">单个IP可以连接到节点的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnectionsPerIP}};最小值为{{defaultConfigs.tcpMinConnectionsPerIP}}。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>单IP TCP新连接速率<em>(分钟)</em></td>
|
||||||
|
<td>
|
||||||
|
<div class="ui fields inline">
|
||||||
|
<div class="ui field">
|
||||||
|
<div class="ui input right labeled">
|
||||||
|
<digit-input name="tcpNewConnectionsRate" v-model="config.tcp.newConnectionsRate" maxlength="6" size="6" style="width: 6em" :min="defaultConfigs.tcpNewConnectionsMinRate"></digit-input>
|
||||||
|
<span class="ui label">个新连接/每分钟</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui field" style="line-height: 2.4em">
|
||||||
|
屏蔽
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<div class="ui input right labeled">
|
||||||
|
<digit-input name="tcpNewConnectionsRateBlockTimeout" v-model="config.tcp.newConnectionsRateBlockTimeout" maxlength="6" size="6" style="width: 5em"></digit-input>
|
||||||
|
<span class="ui label">秒</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="comment">单个IP每分钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsMinutelyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinMinutelyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>单IP TCP新连接速率<em>(秒钟)</em></td>
|
||||||
|
<td>
|
||||||
|
<div class="ui fields inline">
|
||||||
|
<div class="ui field">
|
||||||
|
<div class="ui input right labeled">
|
||||||
|
<digit-input name="tcpNewConnectionsSecondlyRate" v-model="config.tcp.newConnectionsSecondlyRate" maxlength="6" size="6" style="width: 6em" :min="defaultConfigs.tcpNewConnectionsMinRate"></digit-input>
|
||||||
|
<span class="ui label">个新连接/每秒钟</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui field" style="line-height: 2.4em">
|
||||||
|
屏蔽
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<div class="ui input right labeled">
|
||||||
|
<digit-input name="tcpNewConnectionsSecondlyRateBlockTimeout" v-model="config.tcp.newConnectionsSecondlyRateBlockTimeout" maxlength="6" size="6" style="width: 5em"></digit-input>
|
||||||
|
<span class="ui label">秒</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="comment">单个IP每秒钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsSecondlyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinSecondlyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>TCP端口列表</td>
|
||||||
|
<td>
|
||||||
|
<ddos-protection-ports-config-box :v-ports="config.tcp.ports" @change="changeTCPPorts"></ddos-protection-ports-config-box>
|
||||||
|
<p class="comment">在这些端口上使用当前配置。默认为53端口。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>IP白名单</td>
|
||||||
|
<td>
|
||||||
|
<ddos-protection-ip-list-config-box :v-ip-list="config.tcp.allowIPList" @change="changeTCPAllowIPList"></ddos-protection-ip-list-config-box>
|
||||||
|
<p class="comment">在白名单中的IP不受当前设置的限制。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="margin"></div>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
@@ -35,7 +35,8 @@ Vue.component("http-access-log-config-box", {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
accessLog: accessLog,
|
accessLog: accessLog,
|
||||||
hasRequestBodyField: this.vFields.$contains(8)
|
hasRequestBodyField: this.vFields.$contains(8),
|
||||||
|
showAdvancedOptions: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -46,6 +47,9 @@ Vue.component("http-access-log-config-box", {
|
|||||||
return v.code
|
return v.code
|
||||||
})
|
})
|
||||||
this.hasRequestBodyField = this.accessLog.fields.$contains(8)
|
this.hasRequestBodyField = this.accessLog.fields.$contains(8)
|
||||||
|
},
|
||||||
|
changeAdvanced: function (v) {
|
||||||
|
this.showAdvancedOptions = v
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
@@ -63,7 +67,12 @@ Vue.component("http-access-log-config-box", {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
<tbody v-show="((!vIsLocation && !vIsGroup) || accessLog.isPrior) && accessLog.isOn">
|
<tbody v-show="((!vIsLocation && !vIsGroup) || accessLog.isPrior) && accessLog.isOn">
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><more-options-indicator @change="changeAdvanced"></more-options-indicator></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tbody v-show="((!vIsLocation && !vIsGroup) || accessLog.isPrior) && accessLog.isOn && showAdvancedOptions">
|
||||||
<tr>
|
<tr>
|
||||||
<td>基础信息</td>
|
<td>基础信息</td>
|
||||||
<td><p class="comment" style="padding-top: 0">默认记录客户端IP、请求URL等基础信息。</p></td>
|
<td><p class="comment" style="padding-top: 0">默认记录客户端IP、请求URL等基础信息。</p></td>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
Vue.component("http-access-log-partitions-box", {
|
Vue.component("http-access-log-partitions-box", {
|
||||||
props: ["v-partition", "v-day"],
|
props: ["v-partition", "v-day", "v-query"],
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
let that = this
|
let that = this
|
||||||
Tea.action("/servers/logs/partitionData")
|
Tea.action("/servers/logs/partitionData")
|
||||||
@@ -11,13 +11,18 @@ Vue.component("http-access-log-partitions-box", {
|
|||||||
resp.data.partitions.reverse().forEach(function (v) {
|
resp.data.partitions.reverse().forEach(function (v) {
|
||||||
that.partitions.push({
|
that.partitions.push({
|
||||||
code: v,
|
code: v,
|
||||||
isDisabled: false
|
isDisabled: false,
|
||||||
|
hasLogs: false
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
if (that.partitions.length > 0) {
|
if (that.partitions.length > 0) {
|
||||||
if (that.vPartition == null || that.vPartition < 0) {
|
if (that.vPartition == null || that.vPartition < 0) {
|
||||||
that.selectedPartition = that.partitions[0].code
|
that.selectedPartition = that.partitions[0].code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (that.partitions.length > 1) {
|
||||||
|
that.checkLogs()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.post()
|
.post()
|
||||||
@@ -25,7 +30,8 @@ Vue.component("http-access-log-partitions-box", {
|
|||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
partitions: [],
|
partitions: [],
|
||||||
selectedPartition: this.vPartition
|
selectedPartition: this.vPartition,
|
||||||
|
checkingPartition: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -48,12 +54,43 @@ Vue.component("http-access-log-partitions-box", {
|
|||||||
p.isDisabled = true
|
p.isDisabled = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
checkLogs: function () {
|
||||||
|
let that = this
|
||||||
|
let index = this.checkingPartition
|
||||||
|
let params = {
|
||||||
|
partition: index
|
||||||
|
}
|
||||||
|
let query = this.vQuery
|
||||||
|
if (query == null || query.length == 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
query.split("&").forEach(function (v) {
|
||||||
|
let param = v.split("=")
|
||||||
|
params[param[0]] = decodeURIComponent(param[1])
|
||||||
|
})
|
||||||
|
Tea.action("/servers/logs/hasLogs")
|
||||||
|
.params(params)
|
||||||
|
.post()
|
||||||
|
.success(function (response) {
|
||||||
|
if (response.data.hasLogs) {
|
||||||
|
// 因为是倒序,所以这里需要使用总长度减去index
|
||||||
|
that.partitions[that.partitions.length - 1 - index].hasLogs = true
|
||||||
|
}
|
||||||
|
|
||||||
|
index++
|
||||||
|
if (index >= that.partitions.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
that.checkingPartition = index
|
||||||
|
that.checkLogs()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div v-if="partitions.length > 1">
|
template: `<div v-if="partitions.length > 1">
|
||||||
<div class="ui divider" style="margin-bottom: 0"></div>
|
<div class="ui divider" style="margin-bottom: 0"></div>
|
||||||
<div class="ui menu text small blue" style="margin-bottom: 0; margin-top: 0">
|
<div class="ui menu text small blue" style="margin-bottom: 0; margin-top: 0">
|
||||||
<a v-for="(p, index) in partitions" :href="url(p.code)" class="item" :class="{active: selectedPartition == p.code, disabled: p.isDisabled}">分表{{p.code+1}} <span class="disabled" v-if="index != partitions.length - 1">|</span></a>
|
<a v-for="(p, index) in partitions" :href="url(p.code)" class="item" :class="{active: selectedPartition == p.code, disabled: p.isDisabled}">分表{{p.code+1}} <span v-if="p.hasLogs"> <dot></dot></span> <span class="disabled" v-if="index != partitions.length - 1">|</span></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui divider" style="margin-top: 0"></div>
|
<div class="ui divider" style="margin-top: 0"></div>
|
||||||
</div>`
|
</div>`
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ Vue.component("http-auth-config-box", {
|
|||||||
teaweb.popup("/servers/server/settings/access/createPopup", {
|
teaweb.popup("/servers/server/settings/access/createPopup", {
|
||||||
callback: function (resp) {
|
callback: function (resp) {
|
||||||
that.authConfig.policyRefs.push(resp.data.policyRef)
|
that.authConfig.policyRefs.push(resp.data.policyRef)
|
||||||
|
that.change()
|
||||||
},
|
},
|
||||||
height: "28em"
|
height: "28em"
|
||||||
})
|
})
|
||||||
@@ -42,6 +43,7 @@ Vue.component("http-auth-config-box", {
|
|||||||
},
|
},
|
||||||
remove: function (index) {
|
remove: function (index) {
|
||||||
this.authConfig.policyRefs.$remove(index)
|
this.authConfig.policyRefs.$remove(index)
|
||||||
|
this.change()
|
||||||
},
|
},
|
||||||
methodName: function (methodType) {
|
methodName: function (methodType) {
|
||||||
switch (methodType) {
|
switch (methodType) {
|
||||||
@@ -49,8 +51,23 @@ Vue.component("http-auth-config-box", {
|
|||||||
return "BasicAuth"
|
return "BasicAuth"
|
||||||
case "subRequest":
|
case "subRequest":
|
||||||
return "子请求"
|
return "子请求"
|
||||||
|
case "typeA":
|
||||||
|
return "URL鉴权A"
|
||||||
|
case "typeB":
|
||||||
|
return "URL鉴权B"
|
||||||
|
case "typeC":
|
||||||
|
return "URL鉴权C"
|
||||||
|
case "typeD":
|
||||||
|
return "URL鉴权D"
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
|
},
|
||||||
|
change: function () {
|
||||||
|
let that = this
|
||||||
|
setTimeout(function () {
|
||||||
|
// 延时通知,是为了让表单有机会变更数据
|
||||||
|
that.$emit("change", this.authConfig)
|
||||||
|
}, 100)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
@@ -59,7 +76,7 @@ Vue.component("http-auth-config-box", {
|
|||||||
<prior-checkbox :v-config="authConfig" v-if="vIsLocation"></prior-checkbox>
|
<prior-checkbox :v-config="authConfig" v-if="vIsLocation"></prior-checkbox>
|
||||||
<tbody v-show="!vIsLocation || authConfig.isPrior">
|
<tbody v-show="!vIsLocation || authConfig.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">启用认证</td>
|
<td class="title">启用鉴权</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" v-model="authConfig.isOn"/>
|
<input type="checkbox" v-model="authConfig.isOn"/>
|
||||||
@@ -70,14 +87,14 @@ Vue.component("http-auth-config-box", {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div class="margin"></div>
|
<div class="margin"></div>
|
||||||
<!-- 认证方式 -->
|
<!-- 鉴权方式 -->
|
||||||
<div v-show="isOn()">
|
<div v-show="isOn()">
|
||||||
<h4>认证方式</h4>
|
<h4>鉴权方式</h4>
|
||||||
<table class="ui table selectable celled" v-show="authConfig.policyRefs.length > 0">
|
<table class="ui table selectable celled" v-show="authConfig.policyRefs.length > 0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="three wide">名称</th>
|
<th class="three wide">名称</th>
|
||||||
<th class="three wide">认证方法</th>
|
<th class="three wide">鉴权方法</th>
|
||||||
<th>参数</th>
|
<th>参数</th>
|
||||||
<th class="two wide">状态</th>
|
<th class="two wide">状态</th>
|
||||||
<th class="two op">操作</th>
|
<th class="two op">操作</th>
|
||||||
@@ -95,6 +112,15 @@ Vue.component("http-auth-config-box", {
|
|||||||
<span v-if="ref.authPolicy.params.method.length > 0" class="grey">[{{ref.authPolicy.params.method}}]</span>
|
<span v-if="ref.authPolicy.params.method.length > 0" class="grey">[{{ref.authPolicy.params.method}}]</span>
|
||||||
{{ref.authPolicy.params.url}}
|
{{ref.authPolicy.params.url}}
|
||||||
</span>
|
</span>
|
||||||
|
<span v-if="ref.authPolicy.type == 'typeA'">{{ref.authPolicy.params.signParamName}}/有效期{{ref.authPolicy.params.life}}秒</span>
|
||||||
|
<span v-if="ref.authPolicy.type == 'typeB'">有效期{{ref.authPolicy.params.life}}秒</span>
|
||||||
|
<span v-if="ref.authPolicy.type == 'typeC'">有效期{{ref.authPolicy.params.life}}秒</span>
|
||||||
|
<span v-if="ref.authPolicy.type == 'typeD'">{{ref.authPolicy.params.signParamName}}/{{ref.authPolicy.params.timestampParamName}}/有效期{{ref.authPolicy.params.life}}秒</span>
|
||||||
|
|
||||||
|
<div v-if="(ref.authPolicy.params.exts != null && ref.authPolicy.params.exts.length > 0) || (ref.authPolicy.params.domains != null && ref.authPolicy.params.domains.length > 0)">
|
||||||
|
<grey-label v-if="ref.authPolicy.params.exts != null" v-for="ext in ref.authPolicy.params.exts">扩展名:{{ext}}</grey-label>
|
||||||
|
<grey-label v-if="ref.authPolicy.params.domains != null" v-for="domain in ref.authPolicy.params.domains">域名:{{domain}}</grey-label>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<label-on :v-is-on="ref.authPolicy.isOn"></label-on>
|
<label-on :v-is-on="ref.authPolicy.isOn"></label-on>
|
||||||
@@ -106,7 +132,7 @@ Vue.component("http-auth-config-box", {
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<button class="ui button small" type="button" @click.prevent="add">+添加认证方式</button>
|
<button class="ui button small" type="button" @click.prevent="add">+添加鉴权方式</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="margin"></div>
|
<div class="margin"></div>
|
||||||
</div>`
|
</div>`
|
||||||
|
|||||||
@@ -3,6 +3,14 @@ Vue.component("http-cache-ref-box", {
|
|||||||
props: ["v-cache-ref", "v-is-reverse"],
|
props: ["v-cache-ref", "v-is-reverse"],
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
this.$refs.variablesDescriber.update(this.ref.key)
|
this.$refs.variablesDescriber.update(this.ref.key)
|
||||||
|
if (this.ref.simpleCond != null) {
|
||||||
|
this.condType = this.ref.simpleCond.type
|
||||||
|
this.changeCondType(this.ref.simpleCond.type, true)
|
||||||
|
this.condCategory = "simple"
|
||||||
|
} else if (this.ref.conds != null && this.ref.conds.groups != null) {
|
||||||
|
this.condCategory = "complex"
|
||||||
|
}
|
||||||
|
this.changeCondCategory(this.condCategory)
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
let ref = this.vCacheRef
|
let ref = this.vCacheRef
|
||||||
@@ -18,7 +26,8 @@ Vue.component("http-cache-ref-box", {
|
|||||||
skipCacheControlValues: ["private", "no-cache", "no-store"],
|
skipCacheControlValues: ["private", "no-cache", "no-store"],
|
||||||
skipSetCookie: true,
|
skipSetCookie: true,
|
||||||
enableRequestCachePragma: false,
|
enableRequestCachePragma: false,
|
||||||
conds: null,
|
conds: null, // 复杂条件
|
||||||
|
simpleCond: null, // 简单条件
|
||||||
allowChunkedEncoding: true,
|
allowChunkedEncoding: true,
|
||||||
allowPartialContent: false,
|
allowPartialContent: false,
|
||||||
enableIfNoneMatch: false,
|
enableIfNoneMatch: false,
|
||||||
@@ -50,9 +59,22 @@ Vue.component("http-cache-ref-box", {
|
|||||||
if (ref.minSize == null) {
|
if (ref.minSize == null) {
|
||||||
ref.minSize = {count: 0, unit: "kb"}
|
ref.minSize = {count: 0, unit: "kb"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let condType = "url-extension"
|
||||||
|
let condComponent = window.REQUEST_COND_COMPONENTS.$find(function (k, v) {
|
||||||
|
return v.type == "url-extension"
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ref: ref,
|
ref: ref,
|
||||||
moreOptionsVisible: false
|
moreOptionsVisible: false,
|
||||||
|
|
||||||
|
condCategory: "simple", // 条件分类:simple|complex
|
||||||
|
condType: condType,
|
||||||
|
condComponent: condComponent,
|
||||||
|
condIsCaseInsensitive: (ref.simpleCond != null) ? ref.simpleCond.isCaseInsensitive : true,
|
||||||
|
|
||||||
|
components: window.REQUEST_COND_COMPONENTS
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -70,6 +92,7 @@ Vue.component("http-cache-ref-box", {
|
|||||||
},
|
},
|
||||||
changeConds: function (v) {
|
changeConds: function (v) {
|
||||||
this.ref.conds = v
|
this.ref.conds = v
|
||||||
|
this.ref.simpleCond = null
|
||||||
},
|
},
|
||||||
changeStatusList: function (list) {
|
changeStatusList: function (list) {
|
||||||
let result = []
|
let result = []
|
||||||
@@ -92,15 +115,76 @@ Vue.component("http-cache-ref-box", {
|
|||||||
},
|
},
|
||||||
changeExpiresTime: function (expiresTime) {
|
changeExpiresTime: function (expiresTime) {
|
||||||
this.ref.expiresTime = expiresTime
|
this.ref.expiresTime = expiresTime
|
||||||
|
},
|
||||||
|
|
||||||
|
// 切换条件类型
|
||||||
|
changeCondCategory: function (condCategory) {
|
||||||
|
this.condCategory = condCategory
|
||||||
|
|
||||||
|
// resize window
|
||||||
|
let dialog = window.parent.document.querySelector("*[role='dialog']")
|
||||||
|
switch (condCategory) {
|
||||||
|
case "simple":
|
||||||
|
dialog.style.width = "40em"
|
||||||
|
break
|
||||||
|
case "complex":
|
||||||
|
let width = window.parent.innerWidth
|
||||||
|
if (width > 1024) {
|
||||||
|
width = 1024
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.style.width = width + "px"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
changeCondType: function (condType, isInit) {
|
||||||
|
if (!isInit && this.ref.simpleCond != null) {
|
||||||
|
this.ref.simpleCond.value = null
|
||||||
|
}
|
||||||
|
let def = this.components.$find(function (k, component) {
|
||||||
|
return component.type == condType
|
||||||
|
})
|
||||||
|
if (def != null) {
|
||||||
|
this.condComponent = def
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<tbody>
|
template: `<tbody>
|
||||||
<tr>
|
<tr v-if="condCategory == 'simple'">
|
||||||
|
<td class="title color-border">条件类型 *</td>
|
||||||
|
<td>
|
||||||
|
<select class="ui dropdown auto-width" name="condType" v-model="condType" @change="changeCondType(condType, false)">
|
||||||
|
<option value="url-extension">URL扩展名</option>
|
||||||
|
<option value="url-prefix">URL前缀</option>
|
||||||
|
<option value="url-eq-index">首页</option>
|
||||||
|
<option value="url-eq">URL完整路径</option>
|
||||||
|
<option value="url-regexp">URL正则匹配</option>
|
||||||
|
<option value="params">参数匹配</option>
|
||||||
|
</select>
|
||||||
|
<p class="comment"><a href="" @click.prevent="changeCondCategory('complex')">切换到复杂条件 »</a></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="condCategory == 'simple'">
|
||||||
|
<td class="color-border">{{condComponent.paramsTitle}} *</td>
|
||||||
|
<td>
|
||||||
|
<component :is="condComponent.component" :v-cond="ref.simpleCond"></component>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="condCategory == 'simple' && condComponent.caseInsensitive">
|
||||||
|
<td class="color-border">不区分大小写</td>
|
||||||
|
<td>
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input type="checkbox" name="condIsCaseInsensitive" value="1" v-model="condIsCaseInsensitive"/>
|
||||||
|
<label></label>
|
||||||
|
</div>
|
||||||
|
<p class="comment">选中后表示对比时忽略参数值的大小写。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="condCategory == 'complex'">
|
||||||
<td class="title">匹配条件分组 *</td>
|
<td class="title">匹配条件分组 *</td>
|
||||||
<td>
|
<td>
|
||||||
<http-request-conds-box :v-conds="ref.conds" @change="changeConds"></http-request-conds-box>
|
<http-request-conds-box :v-conds="ref.conds" @change="changeConds"></http-request-conds-box>
|
||||||
|
<p class="comment"><a href="" @click.prevent="changeCondCategory('simple')">« 切换到简单条件</a></p>
|
||||||
<input type="hidden" name="cacheRefJSON" :value="JSON.stringify(ref)"/>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-show="!vIsReverse">
|
<tr v-show="!vIsReverse">
|
||||||
@@ -208,5 +292,8 @@ Vue.component("http-cache-ref-box", {
|
|||||||
<p class="comment">特殊情况下才需要开启,可能会降低缓存命中率。</p>
|
<p class="comment">特殊情况下才需要开启,可能会降低缓存命中率。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr v-show="false">
|
||||||
|
<td colspan="2"><input type="hidden" name="cacheRefJSON" :value="JSON.stringify(ref)"/></td>
|
||||||
|
</tr>
|
||||||
</tbody>`
|
</tbody>`
|
||||||
})
|
})
|
||||||
@@ -43,7 +43,10 @@ Vue.component("http-cache-refs-box", {
|
|||||||
</tr>
|
</tr>
|
||||||
<tr v-for="(cacheRef, index) in refs">
|
<tr v-for="(cacheRef, index) in refs">
|
||||||
<td :class="{'color-border': cacheRef.conds.connector == 'and', disabled: !cacheRef.isOn}" :style="{'border-left':cacheRef.isReverse ? '1px #db2828 solid' : ''}">
|
<td :class="{'color-border': cacheRef.conds.connector == 'and', disabled: !cacheRef.isOn}" :style="{'border-left':cacheRef.isReverse ? '1px #db2828 solid' : ''}">
|
||||||
<http-request-conds-view :v-conds="cacheRef.conds" :class="{disabled: !cacheRef.isOn}"></http-request-conds-view>
|
<http-request-conds-view :v-conds="cacheRef.conds" :class="{disabled: !cacheRef.isOn}" v-if="cacheRef.conds != null && cacheRef.conds.groups != null"></http-request-conds-view>
|
||||||
|
<http-request-cond-view :v-cond="cacheRef.simpleCond" v-if="cacheRef.simpleCond != null"></http-request-cond-view>
|
||||||
|
|
||||||
|
<!-- 特殊参数 -->
|
||||||
<grey-label v-if="cacheRef.minSize != null && cacheRef.minSize.count > 0">
|
<grey-label v-if="cacheRef.minSize != null && cacheRef.minSize.count > 0">
|
||||||
{{cacheRef.minSize.count}}{{cacheRef.minSize.unit}}
|
{{cacheRef.minSize.count}}{{cacheRef.minSize.unit}}
|
||||||
<span v-if="cacheRef.maxSize != null && cacheRef.maxSize.count > 0">- {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit}}</span>
|
<span v-if="cacheRef.maxSize != null && cacheRef.maxSize.count > 0">- {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit}}</span>
|
||||||
|
|||||||
@@ -35,17 +35,12 @@ Vue.component("http-cache-refs-config-box", {
|
|||||||
addRef: function (isReverse) {
|
addRef: function (isReverse) {
|
||||||
window.UPDATING_CACHE_REF = null
|
window.UPDATING_CACHE_REF = null
|
||||||
|
|
||||||
let width = window.innerWidth
|
|
||||||
if (width > 1024) {
|
|
||||||
width = 1024
|
|
||||||
}
|
|
||||||
let height = window.innerHeight
|
let height = window.innerHeight
|
||||||
if (height > 500) {
|
if (height > 500) {
|
||||||
height = 500
|
height = 500
|
||||||
}
|
}
|
||||||
let that = this
|
let that = this
|
||||||
teaweb.popup("/servers/server/settings/cache/createPopup?isReverse=" + (isReverse ? 1 : 0), {
|
teaweb.popup("/servers/server/settings/cache/createPopup?isReverse=" + (isReverse ? 1 : 0), {
|
||||||
width: width + "px",
|
|
||||||
height: height + "px",
|
height: height + "px",
|
||||||
callback: function (resp) {
|
callback: function (resp) {
|
||||||
let newRef = resp.data.cacheRef
|
let newRef = resp.data.cacheRef
|
||||||
@@ -82,23 +77,18 @@ Vue.component("http-cache-refs-config-box", {
|
|||||||
updateRef: function (index, cacheRef) {
|
updateRef: function (index, cacheRef) {
|
||||||
window.UPDATING_CACHE_REF = cacheRef
|
window.UPDATING_CACHE_REF = cacheRef
|
||||||
|
|
||||||
let width = window.innerWidth
|
|
||||||
if (width > 1024) {
|
|
||||||
width = 1024
|
|
||||||
}
|
|
||||||
let height = window.innerHeight
|
let height = window.innerHeight
|
||||||
if (height > 500) {
|
if (height > 500) {
|
||||||
height = 500
|
height = 500
|
||||||
}
|
}
|
||||||
let that = this
|
let that = this
|
||||||
teaweb.popup("/servers/server/settings/cache/createPopup", {
|
teaweb.popup("/servers/server/settings/cache/createPopup", {
|
||||||
width: width + "px",
|
|
||||||
height: height + "px",
|
height: height + "px",
|
||||||
callback: function (resp) {
|
callback: function (resp) {
|
||||||
resp.data.cacheRef.id = that.refs[index].id
|
resp.data.cacheRef.id = that.refs[index].id
|
||||||
Vue.set(that.refs, index, resp.data.cacheRef)
|
Vue.set(that.refs, index, resp.data.cacheRef)
|
||||||
that.change()
|
that.change()
|
||||||
that.$refs.cacheRef[index].updateConds(resp.data.cacheRef.conds)
|
that.$refs.cacheRef[index].updateConds(resp.data.cacheRef.conds, resp.data.cacheRef.simpleCond)
|
||||||
that.$refs.cacheRef[index].notifyChange()
|
that.$refs.cacheRef[index].notifyChange()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -186,7 +176,10 @@ Vue.component("http-cache-refs-config-box", {
|
|||||||
<tr>
|
<tr>
|
||||||
<td style="text-align: center;"><i class="icon bars handle grey"></i> </td>
|
<td style="text-align: center;"><i class="icon bars handle grey"></i> </td>
|
||||||
<td :class="{'color-border': cacheRef.conds.connector == 'and', disabled: !cacheRef.isOn}" :style="{'border-left':cacheRef.isReverse ? '1px #db2828 solid' : ''}">
|
<td :class="{'color-border': cacheRef.conds.connector == 'and', disabled: !cacheRef.isOn}" :style="{'border-left':cacheRef.isReverse ? '1px #db2828 solid' : ''}">
|
||||||
<http-request-conds-view :v-conds="cacheRef.conds" ref="cacheRef" :class="{disabled: !cacheRef.isOn}"></http-request-conds-view>
|
<http-request-conds-view :v-conds="cacheRef.conds" ref="cacheRef" :class="{disabled: !cacheRef.isOn}" v-if="cacheRef.conds != null && cacheRef.conds.groups != null"></http-request-conds-view>
|
||||||
|
<http-request-cond-view :v-cond="cacheRef.simpleCond" ref="cacheRef" v-if="cacheRef.simpleCond != null"></http-request-cond-view>
|
||||||
|
|
||||||
|
<!-- 特殊参数 -->
|
||||||
<grey-label v-if="cacheRef.minSize != null && cacheRef.minSize.count > 0">
|
<grey-label v-if="cacheRef.minSize != null && cacheRef.minSize.count > 0">
|
||||||
{{cacheRef.minSize.count}}{{cacheRef.minSize.unit}}
|
{{cacheRef.minSize.count}}{{cacheRef.minSize.unit}}
|
||||||
<span v-if="cacheRef.maxSize != null && cacheRef.maxSize.count > 0">- {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit}}</span>
|
<span v-if="cacheRef.maxSize != null && cacheRef.maxSize.count > 0">- {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit}}</span>
|
||||||
@@ -217,7 +210,7 @@ Vue.component("http-cache-refs-config-box", {
|
|||||||
</table>
|
</table>
|
||||||
<p class="comment" v-if="refs.length > 1">所有条件匹配顺序为从上到下,可以拖动左侧的<i class="icon bars"></i>排序。服务设置的优先级比全局缓存策略设置的优先级要高。</p>
|
<p class="comment" v-if="refs.length > 1">所有条件匹配顺序为从上到下,可以拖动左侧的<i class="icon bars"></i>排序。服务设置的优先级比全局缓存策略设置的优先级要高。</p>
|
||||||
|
|
||||||
<button class="ui button tiny" @click.prevent="addRef(false)" type="button">+添加缓存设置</button> <a href="" @click.prevent="addRef(true)">+添加不缓存设置</a>
|
<button class="ui button tiny" @click.prevent="addRef(false)" type="button">+添加缓存条件</button> <a href="" @click.prevent="addRef(true)">+添加不缓存条件</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="margin"></div>
|
<div class="margin"></div>
|
||||||
</div>`
|
</div>`
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ Vue.component("http-cond-url-extension", {
|
|||||||
template: `<div>
|
template: `<div>
|
||||||
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
||||||
<div v-if="extensions.length > 0">
|
<div v-if="extensions.length > 0">
|
||||||
<div class="ui label small" v-for="(ext, index) in extensions">{{ext}} <a href="" title="删除" @click.prevent="removeExt(index)"><i class="icon remove"></i></a></div>
|
<div class="ui label small basic" v-for="(ext, index) in extensions">{{ext}} <a href="" title="删除" @click.prevent="removeExt(index)"><i class="icon remove"></i></a></div>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui fields inline" v-if="isAdding">
|
<div class="ui fields inline" v-if="isAdding">
|
||||||
@@ -78,18 +78,18 @@ Vue.component("http-cond-url-extension", {
|
|||||||
<input type="text" size="6" maxlength="100" v-model="addingExt" ref="addingExt" placeholder=".xxx" @keyup.enter="confirmAdding" @keypress.enter.prevent="1" />
|
<input type="text" size="6" maxlength="100" v-model="addingExt" ref="addingExt" placeholder=".xxx" @keyup.enter="confirmAdding" @keypress.enter.prevent="1" />
|
||||||
</div>
|
</div>
|
||||||
<div class="ui field">
|
<div class="ui field">
|
||||||
<button class="ui button tiny" type="button" @click.prevent="confirmAdding">确认</button>
|
<button class="ui button tiny basic" type="button" @click.prevent="confirmAdding">确认</button>
|
||||||
<a href="" title="取消" @click.prevent="cancelAdding"><i class="icon remove"></i></a>
|
<a href="" title="取消" @click.prevent="cancelAdding"><i class="icon remove"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 1em">
|
<div style="margin-top: 1em" v-show="!isAdding">
|
||||||
<button class="ui button tiny" type="button" @click.prevent="addExt()">+添加扩展名</button>
|
<button class="ui button tiny basic" type="button" @click.prevent="addExt()">+添加扩展名</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="comment">扩展名需要包含点(.)符号,例如<span class="ui label tiny">.jpg</span>、<span class="ui label tiny">.png</span>之类。</p>
|
<p class="comment">扩展名需要包含点(.)符号,例如<code-label>.jpg</code-label>、<code-label>.png</code-label>之类。</p>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
// URL扩展名条件
|
// 排除URL扩展名条件
|
||||||
Vue.component("http-cond-url-not-extension", {
|
Vue.component("http-cond-url-not-extension", {
|
||||||
props: ["v-cond"],
|
props: ["v-cond"],
|
||||||
data: function () {
|
data: function () {
|
||||||
@@ -161,7 +161,7 @@ Vue.component("http-cond-url-not-extension", {
|
|||||||
template: `<div>
|
template: `<div>
|
||||||
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
||||||
<div v-if="extensions.length > 0">
|
<div v-if="extensions.length > 0">
|
||||||
<div class="ui label small" v-for="(ext, index) in extensions">{{ext}} <a href="" title="删除" @click.prevent="removeExt(index)"><i class="icon remove"></i></a></div>
|
<div class="ui label small basic" v-for="(ext, index) in extensions">{{ext}} <a href="" title="删除" @click.prevent="removeExt(index)"><i class="icon remove"></i></a></div>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui fields inline" v-if="isAdding">
|
<div class="ui fields inline" v-if="isAdding">
|
||||||
@@ -169,20 +169,23 @@ Vue.component("http-cond-url-not-extension", {
|
|||||||
<input type="text" size="6" maxlength="100" v-model="addingExt" ref="addingExt" placeholder=".xxx" @keyup.enter="confirmAdding" @keypress.enter.prevent="1" />
|
<input type="text" size="6" maxlength="100" v-model="addingExt" ref="addingExt" placeholder=".xxx" @keyup.enter="confirmAdding" @keypress.enter.prevent="1" />
|
||||||
</div>
|
</div>
|
||||||
<div class="ui field">
|
<div class="ui field">
|
||||||
<button class="ui button tiny" type="button" @click.prevent="confirmAdding">确认</button>
|
<button class="ui button tiny basic" type="button" @click.prevent="confirmAdding">确认</button>
|
||||||
<a href="" title="取消" @click.prevent="cancelAdding"><i class="icon remove"></i></a>
|
<a href="" title="取消" @click.prevent="cancelAdding"><i class="icon remove"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 1em">
|
<div style="margin-top: 1em" v-show="!isAdding">
|
||||||
<button class="ui button tiny" type="button" @click.prevent="addExt()">+添加扩展名</button>
|
<button class="ui button tiny basic" type="button" @click.prevent="addExt()">+添加扩展名</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="comment">扩展名需要包含点(.)符号,例如<span class="ui label tiny">.jpg</span>、<span class="ui label tiny">.png</span>之类。</p>
|
<p class="comment">扩展名需要包含点(.)符号,例如<code-label>.jpg</code-label>、<code-label>.png</code-label>之类。</p>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
// 根据URL前缀
|
// 根据URL前缀
|
||||||
Vue.component("http-cond-url-prefix", {
|
Vue.component("http-cond-url-prefix", {
|
||||||
props: ["v-cond"],
|
props: ["v-cond"],
|
||||||
|
mounted: function () {
|
||||||
|
this.$refs.valueInput.focus()
|
||||||
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
let cond = {
|
let cond = {
|
||||||
isRequest: true,
|
isRequest: true,
|
||||||
@@ -205,13 +208,16 @@ Vue.component("http-cond-url-prefix", {
|
|||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
||||||
<input type="text" v-model="cond.value"/>
|
<input type="text" v-model="cond.value" ref="valueInput"/>
|
||||||
<p class="comment">URL前缀,有此前缀的URL都将会被匹配,通常以<code-label>/</code-label>开头,比如<code-label>/static</code-label>。</p>
|
<p class="comment">URL前缀,有此前缀的URL都将会被匹配,通常以<code-label>/</code-label>开头,比如<code-label>/static</code-label>、<code-label>/images</code-label>,不需要带域名。</p>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
Vue.component("http-cond-url-not-prefix", {
|
Vue.component("http-cond-url-not-prefix", {
|
||||||
props: ["v-cond"],
|
props: ["v-cond"],
|
||||||
|
mounted: function () {
|
||||||
|
this.$refs.valueInput.focus()
|
||||||
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
let cond = {
|
let cond = {
|
||||||
isRequest: true,
|
isRequest: true,
|
||||||
@@ -235,14 +241,47 @@ Vue.component("http-cond-url-not-prefix", {
|
|||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
||||||
<input type="text" v-model="cond.value"/>
|
<input type="text" v-model="cond.value" ref="valueInput"/>
|
||||||
<p class="comment">要排除的URL前缀,有此前缀的URL都将会被匹配,通常以<code-label>/</code-label>开头,比如<code-label>/static</code-label>。</p>
|
<p class="comment">要排除的URL前缀,有此前缀的URL都将会被匹配,通常以<code-label>/</code-label>开头,比如<code-label>/static</code-label>、<code-label>/images</code-label>,不需要带域名。</p>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
|
|
||||||
|
// 首页
|
||||||
|
Vue.component("http-cond-url-eq-index", {
|
||||||
|
props: ["v-cond"],
|
||||||
|
data: function () {
|
||||||
|
let cond = {
|
||||||
|
isRequest: true,
|
||||||
|
param: "${requestPath}",
|
||||||
|
operator: "eq",
|
||||||
|
value: "/",
|
||||||
|
isCaseInsensitive: false
|
||||||
|
}
|
||||||
|
if (this.vCond != null && typeof this.vCond.value == "string") {
|
||||||
|
cond.value = this.vCond.value
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
cond: cond
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
changeCaseInsensitive: function (isCaseInsensitive) {
|
||||||
|
this.cond.isCaseInsensitive = isCaseInsensitive
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
||||||
|
<input type="text" v-model="cond.value" disabled="disabled" style="background: #eee"/>
|
||||||
|
<p class="comment">检查URL路径是为<code-label>/</code-label>,不需要带域名。</p>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
// URL精准匹配
|
// URL精准匹配
|
||||||
Vue.component("http-cond-url-eq", {
|
Vue.component("http-cond-url-eq", {
|
||||||
props: ["v-cond"],
|
props: ["v-cond"],
|
||||||
|
mounted: function () {
|
||||||
|
this.$refs.valueInput.focus()
|
||||||
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
let cond = {
|
let cond = {
|
||||||
isRequest: true,
|
isRequest: true,
|
||||||
@@ -265,13 +304,16 @@ Vue.component("http-cond-url-eq", {
|
|||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
||||||
<input type="text" v-model="cond.value"/>
|
<input type="text" v-model="cond.value" ref="valueInput"/>
|
||||||
<p class="comment">完整的URL路径,通常以<code-label>/</code-label>开头,比如<code-label>/static/ui.js</code-label>,并不包含域名部分。</p>
|
<p class="comment">完整的URL路径,通常以<code-label>/</code-label>开头,比如<code-label>/static/ui.js</code-label>,不需要带域名。</p>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
Vue.component("http-cond-url-not-eq", {
|
Vue.component("http-cond-url-not-eq", {
|
||||||
props: ["v-cond"],
|
props: ["v-cond"],
|
||||||
|
mounted: function () {
|
||||||
|
this.$refs.valueInput.focus()
|
||||||
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
let cond = {
|
let cond = {
|
||||||
isRequest: true,
|
isRequest: true,
|
||||||
@@ -295,14 +337,17 @@ Vue.component("http-cond-url-not-eq", {
|
|||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
||||||
<input type="text" v-model="cond.value"/>
|
<input type="text" v-model="cond.value" ref="valueInput"/>
|
||||||
<p class="comment">要排除的完整的URL路径,通常以<code-label>/</code-label>开头,比如<code-label>/static/ui.js</code-label>,并不包含域名部分。</p>
|
<p class="comment">要排除的完整的URL路径,通常以<code-label>/</code-label>开头,比如<code-label>/static/ui.js</code-label>,不需要带域名。</p>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
// URL正则匹配
|
// URL正则匹配
|
||||||
Vue.component("http-cond-url-regexp", {
|
Vue.component("http-cond-url-regexp", {
|
||||||
props: ["v-cond"],
|
props: ["v-cond"],
|
||||||
|
mounted: function () {
|
||||||
|
this.$refs.valueInput.focus()
|
||||||
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
let cond = {
|
let cond = {
|
||||||
isRequest: true,
|
isRequest: true,
|
||||||
@@ -325,14 +370,17 @@ Vue.component("http-cond-url-regexp", {
|
|||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
||||||
<input type="text" v-model="cond.value"/>
|
<input type="text" v-model="cond.value" ref="valueInput"/>
|
||||||
<p class="comment">匹配URL的正则表达式,比如<code-label>^/static/(.*).js$</code-label>。</p>
|
<p class="comment">匹配URL的正则表达式,比如<code-label>^/static/(.*).js$</code-label>,不需要带域名。</p>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
// 排除URL正则匹配
|
// 排除URL正则匹配
|
||||||
Vue.component("http-cond-url-not-regexp", {
|
Vue.component("http-cond-url-not-regexp", {
|
||||||
props: ["v-cond"],
|
props: ["v-cond"],
|
||||||
|
mounted: function () {
|
||||||
|
this.$refs.valueInput.focus()
|
||||||
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
let cond = {
|
let cond = {
|
||||||
isRequest: true,
|
isRequest: true,
|
||||||
@@ -355,8 +403,8 @@ Vue.component("http-cond-url-not-regexp", {
|
|||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
||||||
<input type="text" v-model="cond.value"/>
|
<input type="text" v-model="cond.value" ref="valueInput"/>
|
||||||
<p class="comment"><strong>不要</strong>匹配URL的正则表达式,意即只要匹配成功则排除此条件,比如<code-label>^/static/(.*).js$</code-label>。</p>
|
<p class="comment"><strong>不要</strong>匹配URL的正则表达式,意即只要匹配成功则排除此条件,比如<code-label>^/static/(.*).js$</code-label>,不需要带域名。</p>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -364,6 +412,9 @@ Vue.component("http-cond-url-not-regexp", {
|
|||||||
// User-Agent正则匹配
|
// User-Agent正则匹配
|
||||||
Vue.component("http-cond-user-agent-regexp", {
|
Vue.component("http-cond-user-agent-regexp", {
|
||||||
props: ["v-cond"],
|
props: ["v-cond"],
|
||||||
|
mounted: function () {
|
||||||
|
this.$refs.valueInput.focus()
|
||||||
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
let cond = {
|
let cond = {
|
||||||
isRequest: true,
|
isRequest: true,
|
||||||
@@ -386,7 +437,7 @@ Vue.component("http-cond-user-agent-regexp", {
|
|||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
||||||
<input type="text" v-model="cond.value"/>
|
<input type="text" v-model="cond.value" ref="valueInput"/>
|
||||||
<p class="comment">匹配User-Agent的正则表达式,比如<code-label>Android|iPhone</code-label>。</p>
|
<p class="comment">匹配User-Agent的正则表达式,比如<code-label>Android|iPhone</code-label>。</p>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
@@ -394,6 +445,9 @@ Vue.component("http-cond-user-agent-regexp", {
|
|||||||
// User-Agent正则不匹配
|
// User-Agent正则不匹配
|
||||||
Vue.component("http-cond-user-agent-not-regexp", {
|
Vue.component("http-cond-user-agent-not-regexp", {
|
||||||
props: ["v-cond"],
|
props: ["v-cond"],
|
||||||
|
mounted: function () {
|
||||||
|
this.$refs.valueInput.focus()
|
||||||
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
let cond = {
|
let cond = {
|
||||||
isRequest: true,
|
isRequest: true,
|
||||||
@@ -416,7 +470,7 @@ Vue.component("http-cond-user-agent-not-regexp", {
|
|||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
<input type="hidden" name="condJSON" :value="JSON.stringify(cond)"/>
|
||||||
<input type="text" v-model="cond.value"/>
|
<input type="text" v-model="cond.value" ref="valueInput"/>
|
||||||
<p class="comment">匹配User-Agent的正则表达式,比如<code-label>Android|iPhone</code-label>,如果匹配,则排除此条件。</p>
|
<p class="comment">匹配User-Agent的正则表达式,比如<code-label>Android|iPhone</code-label>,如果匹配,则排除此条件。</p>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
@@ -490,12 +544,12 @@ Vue.component("http-cond-mime-type", {
|
|||||||
<input type="text" size="16" maxlength="100" v-model="addingMimeType" ref="addingMimeType" placeholder="类似于image/png" @keyup.enter="confirmAdding" @keypress.enter.prevent="1" />
|
<input type="text" size="16" maxlength="100" v-model="addingMimeType" ref="addingMimeType" placeholder="类似于image/png" @keyup.enter="confirmAdding" @keypress.enter.prevent="1" />
|
||||||
</div>
|
</div>
|
||||||
<div class="ui field">
|
<div class="ui field">
|
||||||
<button class="ui button tiny" type="button" @click.prevent="confirmAdding">确认</button>
|
<button class="ui button tiny basic" type="button" @click.prevent="confirmAdding">确认</button>
|
||||||
<a href="" title="取消" @click.prevent="cancelAdding"><i class="icon remove"></i></a>
|
<a href="" title="取消" @click.prevent="cancelAdding"><i class="icon remove"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 1em">
|
<div style="margin-top: 1em">
|
||||||
<button class="ui button tiny" type="button" @click.prevent="addMimeType()">+添加MimeType</button>
|
<button class="ui button tiny basic" type="button" @click.prevent="addMimeType()">+添加MimeType</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="comment">服务器返回的内容的MimeType,比如<span class="ui label tiny">text/html</span>、<span class="ui label tiny">image/*</span>等。</p>
|
<p class="comment">服务器返回的内容的MimeType,比如<span class="ui label tiny">text/html</span>、<span class="ui label tiny">image/*</span>等。</p>
|
||||||
</div>`
|
</div>`
|
||||||
|
|||||||
@@ -78,8 +78,11 @@ Vue.component("http-firewall-actions-box", {
|
|||||||
captchaLife: "",
|
captchaLife: "",
|
||||||
captchaMaxFails: "",
|
captchaMaxFails: "",
|
||||||
captchaFailBlockTimeout: "",
|
captchaFailBlockTimeout: "",
|
||||||
|
|
||||||
get302Life: "",
|
get302Life: "",
|
||||||
|
|
||||||
post307Life: "",
|
post307Life: "",
|
||||||
|
|
||||||
recordIPType: "black",
|
recordIPType: "black",
|
||||||
recordIPLevel: "critical",
|
recordIPLevel: "critical",
|
||||||
recordIPTimeout: "",
|
recordIPTimeout: "",
|
||||||
@@ -97,7 +100,11 @@ Vue.component("http-firewall-actions-box", {
|
|||||||
goGroup: null,
|
goGroup: null,
|
||||||
|
|
||||||
goSetId: 0,
|
goSetId: 0,
|
||||||
goSetName: ""
|
goSetName: "",
|
||||||
|
|
||||||
|
jsCookieLife: "",
|
||||||
|
jsCookieMaxFails: "",
|
||||||
|
jsCookieFailBlockTimeout: ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -195,7 +202,31 @@ Vue.component("http-firewall-actions-box", {
|
|||||||
} else {
|
} else {
|
||||||
this.goSetName = set.name
|
this.goSetName = set.name
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
jsCookieLife: function (v) {
|
||||||
|
v = parseInt(v)
|
||||||
|
if (isNaN(v)) {
|
||||||
|
this.actionOptions["life"] = 0
|
||||||
|
} else {
|
||||||
|
this.actionOptions["life"] = v
|
||||||
|
}
|
||||||
|
},
|
||||||
|
jsCookieMaxFails: function (v) {
|
||||||
|
v = parseInt(v)
|
||||||
|
if (isNaN(v)) {
|
||||||
|
this.actionOptions["maxFails"] = 0
|
||||||
|
} else {
|
||||||
|
this.actionOptions["maxFails"] = v
|
||||||
|
}
|
||||||
|
},
|
||||||
|
jsCookieFailBlockTimeout: function (v) {
|
||||||
|
v = parseInt(v)
|
||||||
|
if (isNaN(v)) {
|
||||||
|
this.actionOptions["failBlockTimeout"] = 0
|
||||||
|
} else {
|
||||||
|
this.actionOptions["failBlockTimeout"] = v
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
add: function () {
|
add: function () {
|
||||||
@@ -207,10 +238,17 @@ Vue.component("http-firewall-actions-box", {
|
|||||||
// 动作参数
|
// 动作参数
|
||||||
this.blockTimeout = ""
|
this.blockTimeout = ""
|
||||||
this.blockScope = "global"
|
this.blockScope = "global"
|
||||||
|
|
||||||
this.captchaLife = ""
|
this.captchaLife = ""
|
||||||
this.captchaMaxFails = ""
|
this.captchaMaxFails = ""
|
||||||
this.captchaFailBlockTimeout = ""
|
this.captchaFailBlockTimeout = ""
|
||||||
|
|
||||||
|
this.jsCookieLife = ""
|
||||||
|
this.jsCookieMaxFails = ""
|
||||||
|
this.jsCookieFailBlockTimeout = ""
|
||||||
|
|
||||||
this.get302Life = ""
|
this.get302Life = ""
|
||||||
|
|
||||||
this.post307Life = ""
|
this.post307Life = ""
|
||||||
|
|
||||||
this.recordIPLevel = "critical"
|
this.recordIPLevel = "critical"
|
||||||
@@ -287,6 +325,20 @@ Vue.component("http-firewall-actions-box", {
|
|||||||
this.captchaFailBlockTimeout = config.options.failBlockTimeout.toString()
|
this.captchaFailBlockTimeout = config.options.failBlockTimeout.toString()
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case "js_cookie":
|
||||||
|
this.jsCookieLife = ""
|
||||||
|
if (config.options.life != null || config.options.life > 0) {
|
||||||
|
this.jsCookieLife = config.options.life.toString()
|
||||||
|
}
|
||||||
|
this.jsCookieMaxFails = ""
|
||||||
|
if (config.options.maxFails != null || config.options.maxFails > 0) {
|
||||||
|
this.jsCookieMaxFails = config.options.maxFails.toString()
|
||||||
|
}
|
||||||
|
this.jsCookieFailBlockTimeout = ""
|
||||||
|
if (config.options.failBlockTimeout != null || config.options.failBlockTimeout > 0) {
|
||||||
|
this.jsCookieFailBlockTimeout = config.options.failBlockTimeout.toString()
|
||||||
|
}
|
||||||
|
break
|
||||||
case "notify":
|
case "notify":
|
||||||
break
|
break
|
||||||
case "get_302":
|
case "get_302":
|
||||||
@@ -539,6 +591,11 @@ Vue.component("http-firewall-actions-box", {
|
|||||||
<span v-if="config.options.maxFails > 0"> / 最多失败{{config.options.maxFails}}次</span>
|
<span v-if="config.options.maxFails > 0"> / 最多失败{{config.options.maxFails}}次</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
<!-- js cookie -->
|
||||||
|
<span v-if="config.code == 'js_cookie' && config.options.life > 0">:有效期{{config.options.life}}秒
|
||||||
|
<span v-if="config.options.maxFails > 0"> / 最多失败{{config.options.maxFails}}次</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
<!-- get 302 -->
|
<!-- get 302 -->
|
||||||
<span v-if="config.code == 'get_302' && config.options.life > 0">:有效期{{config.options.life}}秒</span>
|
<span v-if="config.code == 'get_302' && config.options.life > 0">:有效期{{config.options.life}}秒</span>
|
||||||
|
|
||||||
@@ -638,6 +695,38 @@ Vue.component("http-firewall-actions-box", {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<!-- js cookie -->
|
||||||
|
<tr v-if="actionCode == 'js_cookie'">
|
||||||
|
<td>有效时间</td>
|
||||||
|
<td>
|
||||||
|
<div class="ui input right labeled">
|
||||||
|
<input type="text" style="width: 5em" maxlength="9" v-model="jsCookieLife" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
|
||||||
|
<span class="ui label">秒</span>
|
||||||
|
</div>
|
||||||
|
<p class="comment">验证通过后在这个时间内不再验证;如果为空或者为0表示默认。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="actionCode == 'js_cookie'">
|
||||||
|
<td>最多失败次数</td>
|
||||||
|
<td>
|
||||||
|
<div class="ui input right labeled">
|
||||||
|
<input type="text" style="width: 5em" maxlength="9" v-model="jsCookieMaxFails" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
|
||||||
|
<span class="ui label">次</span>
|
||||||
|
</div>
|
||||||
|
<p class="comment">允许用户失败尝试的最多次数,超过这个次数将被自动加入黑名单;如果为空或者为0表示默认。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="actionCode == 'js_cookie'">
|
||||||
|
<td>失败拦截时间</td>
|
||||||
|
<td>
|
||||||
|
<div class="ui input right labeled">
|
||||||
|
<input type="text" style="width: 5em" maxlength="9" v-model="jsCookieFailBlockTimeout" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
|
||||||
|
<span class="ui label">秒</span>
|
||||||
|
</div>
|
||||||
|
<p class="comment">在达到最多失败次数(大于0)时,自动拦截的时间;如果为空或者为0表示默认。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<!-- get_302 -->
|
<!-- get_302 -->
|
||||||
<tr v-if="actionCode == 'get_302'">
|
<tr v-if="actionCode == 'get_302'">
|
||||||
<td>有效时间</td>
|
<td>有效时间</td>
|
||||||
|
|||||||
@@ -183,6 +183,13 @@ Vue.component("http-firewall-checkpoint-cc", {
|
|||||||
value: ignoreCommonFiles
|
value: ignoreCommonFiles
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
thresholdTooLow: function () {
|
||||||
|
let threshold = parseInt(this.threshold.toString())
|
||||||
|
if (isNaN(threshold) || threshold <= 0) {
|
||||||
|
threshold = 1000
|
||||||
|
}
|
||||||
|
return threshold > 0 && threshold < 5
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
@@ -208,6 +215,7 @@ Vue.component("http-firewall-checkpoint-cc", {
|
|||||||
<td>阈值 *</td>
|
<td>阈值 *</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" v-model="threshold" style="width: 6em" maxlength="8"/>
|
<input type="text" v-model="threshold" style="width: 6em" maxlength="8"/>
|
||||||
|
<p class="comment" v-if="thresholdTooLow()"><span class="red">对于网站类应用来说,当前阈值设置的太低,有可能会影响用户正常访问。</span></p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
38
web/public/js/components/server/http-request-cond-view.js
Normal file
38
web/public/js/components/server/http-request-cond-view.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
Vue.component("http-request-cond-view", {
|
||||||
|
props: ["v-cond"],
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
cond: this.vCond,
|
||||||
|
components: window.REQUEST_COND_COMPONENTS
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
typeName: function (cond) {
|
||||||
|
let c = this.components.$find(function (k, v) {
|
||||||
|
return v.type == cond.type
|
||||||
|
})
|
||||||
|
if (c != null) {
|
||||||
|
return c.name;
|
||||||
|
}
|
||||||
|
return cond.param + " " + cond.operator
|
||||||
|
},
|
||||||
|
updateConds: function (conds, simpleCond) {
|
||||||
|
for (let k in simpleCond) {
|
||||||
|
if (simpleCond.hasOwnProperty(k)) {
|
||||||
|
this.cond[k] = simpleCond[k]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notifyChange: function () {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div style="margin-bottom: 0.5em">
|
||||||
|
<span class="ui label small basic">
|
||||||
|
<var v-if="cond.type.length == 0 || cond.type == 'params'" style="font-style: normal">{{cond.param}} <var>{{cond.operator}}</var></var>
|
||||||
|
<var v-if="cond.type.length > 0 && cond.type != 'params'" style="font-style: normal">{{typeName(cond)}}: </var>
|
||||||
|
{{cond.value}}
|
||||||
|
<sup v-if="cond.isCaseInsensitive" title="不区分大小写"><i class="icon info small"></i></sup>
|
||||||
|
</span>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
@@ -9,6 +9,9 @@ Vue.component("http-request-conds-box", {
|
|||||||
groups: []
|
groups: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (conds.groups == null) {
|
||||||
|
conds.groups = []
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
conds: conds,
|
conds: conds,
|
||||||
components: window.REQUEST_COND_COMPONENTS
|
components: window.REQUEST_COND_COMPONENTS
|
||||||
@@ -102,7 +105,7 @@ Vue.component("http-request-conds-box", {
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<button class="ui button tiny" type="button" @click.prevent="addGroup()">+添加分组</button>
|
<button class="ui button tiny basic" type="button" @click.prevent="addGroup()">+添加分组</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ Vue.component("http-request-conds-view", {
|
|||||||
groups: []
|
groups: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (conds.groups == null) {
|
||||||
|
conds.groups = []
|
||||||
|
}
|
||||||
|
|
||||||
let that = this
|
let that = this
|
||||||
conds.groups.forEach(function (group) {
|
conds.groups.forEach(function (group) {
|
||||||
@@ -43,12 +46,14 @@ Vue.component("http-request-conds-view", {
|
|||||||
},
|
},
|
||||||
notifyChange: function () {
|
notifyChange: function () {
|
||||||
let that = this
|
let that = this
|
||||||
this.initConds.groups.forEach(function (group) {
|
if (this.initConds.groups != null) {
|
||||||
group.conds.forEach(function (cond) {
|
this.initConds.groups.forEach(function (group) {
|
||||||
cond.typeName = that.typeName(cond)
|
group.conds.forEach(function (cond) {
|
||||||
|
cond.typeName = that.typeName(cond)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
this.$forceUpdate()
|
||||||
this.$forceUpdate()
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ Vue.component("http-request-limit-config-box", {
|
|||||||
<td>单IP最大并发连接数</td>
|
<td>单IP最大并发连接数</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" maxlength="6" v-model="maxConnsPerIP"/>
|
<input type="text" maxlength="6" v-model="maxConnsPerIP"/>
|
||||||
<p class="comment">单IP最大连接数,统计单个IP总连接数时不区分服务,超出此限制则响应用户<code-label>429</code-label>代码。为0表示不限制。</p>
|
<p class="comment">单IP最大连接数,统计单个IP总连接数时不区分服务,超出此限制则响应用户<code-label>429</code-label>代码。为0表示不限制。<span v-if="maxConnsPerIP <= 3" class="red">当前设置的并发连接数过低,可能会影响正常用户访问,建议不小于3。</span></p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -7,6 +7,15 @@
|
|||||||
"paramsTitle": "扩展名列表",
|
"paramsTitle": "扩展名列表",
|
||||||
"isRequest": true
|
"isRequest": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "url-eq-index",
|
||||||
|
"name": "首页",
|
||||||
|
"description": "检查URL路径是为\"/\"",
|
||||||
|
"component": "http-cond-url-eq-index",
|
||||||
|
"paramsTitle": "URL完整路径",
|
||||||
|
"isRequest": true,
|
||||||
|
"caseInsensitive": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "url-prefix",
|
"type": "url-prefix",
|
||||||
"name": "URL前缀",
|
"name": "URL前缀",
|
||||||
@@ -18,7 +27,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "url-eq",
|
"type": "url-eq",
|
||||||
"name": "URL精准匹配",
|
"name": "URL完整路径",
|
||||||
"description": "检查URL中的文件路径是否一致",
|
"description": "检查URL中的文件路径是否一致",
|
||||||
"component": "http-cond-url-eq",
|
"component": "http-cond-url-eq",
|
||||||
"paramsTitle": "URL完整路径",
|
"paramsTitle": "URL完整路径",
|
||||||
@@ -70,7 +79,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "url-not-eq",
|
"type": "url-not-eq",
|
||||||
"name": "排除:URL精准匹配",
|
"name": "排除:URL完整路径",
|
||||||
"description": "检查URL中的文件路径是否一致",
|
"description": "检查URL中的文件路径是否一致",
|
||||||
"component": "http-cond-url-not-eq",
|
"component": "http-cond-url-not-eq",
|
||||||
"paramsTitle": "URL完整路径",
|
"paramsTitle": "URL完整路径",
|
||||||
|
|||||||
@@ -561,6 +561,7 @@ window.teaweb = {
|
|||||||
|
|
||||||
let chartBox = document.getElementById(chartId)
|
let chartBox = document.getElementById(chartId)
|
||||||
if (chartBox == null) {
|
if (chartBox == null) {
|
||||||
|
console.error("chart id '" + chartId + "' not found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let chart = this.initChart(chartBox)
|
let chart = this.initChart(chartBox)
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ div.comment {
|
|||||||
color: rgba(0, 0, 0, 0.4);
|
color: rgba(0, 0, 0, 0.4);
|
||||||
padding-top: 0.4em;
|
padding-top: 0.4em;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
p.comment em,
|
p.comment em,
|
||||||
div.comment em {
|
div.comment em {
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"sources":["@layout_popup.less"],"names":[],"mappings":";AACA;EACC,WAAA;;AAGD;EACC,aAAA;;AAGD;EACC,qBAAA;;AAGD,CAAC;AAAW,CAAC,SAAS;AAAQ,CAAC,SAAS;AAAS,IAAI;EACpD,WAAA;;AAGD,CAAC;AAAU,IAAI;AAAU,IAAI;EAC5B,cAAA;;AAGD,IAAI;AAAO,KAAK;AAAO,CAAC;EACvB,sBAAA;;AAGD,CAAC;EACA,iBAAA;;AAGD,IAAI;AAAM,GAAG;EACZ,cAAA;;AAGD,IAAI;EACH,cAAA;;AAGD,GAAG,IAAI;EACN,mBAAmB,8CAAnB;;AAGD;EACC,uBAAA;;AAGD,MAAM;EACL,sBAAA;;AAGD,MAAM;EACL,sBAAA;;AAGD,MAAM;EACL,sBAAA;;AAGD,MAAO;AAAI,MAAO;EACjB,gBAAA;;AAGD,CAAC;AAAU,GAAG;EACb,yBAAA;EACA,kBAAA;EACA,mBAAA;;AAGD,CAAC,QAAS;AAAI,GAAG,QAAS;EACzB,6BAAA;;AAGD;EACC,mBAAA;EACA,2BAAA;EACA,gBAAA;EACA,uBAAA;;AAGD,GAAG;AAAS,CAAC;EACZ,eAAA;;;AAID,GAAG;EACF,UAAA;;AAGD,GAAG;EACF,YAAA;;AAGD,GAAG;EACF,UAAA;;AAGD,GAAG;EACF,WAAA;;;AAID,MAAM;EACL,cAAA;;;AAID;EACC,kBAAA;EACA,UAAA;EACA,UAAA;EACA,mBAAA;EACA,kBAAA;EACA,UAAA;;AAGD,mBAAqC;EACpC;IACC,SAAA;;;AAIF,KAAK;EACJ,SAAA;;AAGD,KAAK;EACJ,UAAA;;AAGD,mBAAqC;EACpC,KAAK;IACJ,SAAA;;;AAIF,KAAM,MAAM,GAAE;EACb,WAAA;;AAGD,KAAM,MAAM,GAAE;EACb,WAAA;;AAGD,KAAM,MAAM;EACX,mBAAA;;AAGD,KAAM,GAAE;EACP,8BAAA;;AAGD,KAAM,MAAM,GAAE;EACb,mBAAA;;AAGD,KAAM,MAAM,GAAE;EACb,sBAAA;;AAGD,KAAM,MAAM,GAAE,aAAc;EAC3B,mBAAA;;AAGD,KAAM,MAAM,GAAG;EACd,mBAAA;EACA,kBAAA;EACA,gBAAA;;AAGD,KAAM;EACL,mBAAA;EACA,iBAAA;;AAGD,KAAM,GAAG;EACR,gBAAA;;AAGD,KAAM,GAAG,KAAI;EACZ,cAAA;;AAGD,KAAM,GAAG;EACR,gBAAA;EACA,0BAAA;EACA,UAAA;;AAGD,KAAM,GAAG,EAAC;EACT,SAAS,GAAT;;AAGD,KAAM,GAAG,EAAC;EACT,SAAS,GAAT;;AAGD,KAAM;EACL,mBAAA;;AAGD,KAAM,GAAG,KAAI;EACZ,gBAAA;;AAGD,KAAM,QAAO;EACZ,gBAAA;EACA,cAAA;EACA,gBAAA;;;AAID,KAAK;EACJ,gBAAA;;AAGD,KAAK,KAAK;EACT,UAAA;EACA,WAAA;;;AAID;EACC,wBAAA;;;AAID,iBAAkB;EACjB,gBAAA;;AAGD,iBAAkB,MAAK;EACtB,UAAA;;AAGD,iBAAkB,MAAM;EACvB,2BAAA;;AAGD,MAAM;EACL,sBAAA;;;AAID,mBAAqC;EACpC,OAAO,IAAI;IACV,sBAAA;;;;AAKF,KAAK;EACJ,0BAAA;;AAGD,KAAK;EACJ,cAAA;;;AAOD,WAAY,MAAK;EAChB,wBAAA;EACA,2BAAA;;AAGD,WAAY;EACX,wBAAA;EACA,2BAAA;;AAGD,YAAa,MAAK;EACjB,wBAAA;EACA,2BAAA;;AAGD,YAAa,MAAK,KAAM;EACvB,kBAAA;;AAGD,YAAa;EACZ,wBAAA;;AAGD,KAAM;EACL,aAAA;;;AAID,IAAI;AAAQ,GAAG;EACd,cAAA;;AAGD,GAAG;EACF,8BAAA;;;AAID,QAAS;EACR,WAAA;EACA,kBAAA;;;AAID,SAAU,MAAM;AAAG,SAAU;EAC5B,gBAAA;;;AAID;EACC,eAAA;EAEA,2BAAA;;AAHD,KAKC;EACC,qBAAA;EACA,mBAAA;EACA,WAAA;EACA,iBAAA;EACA,SAAA;EACA,gBAAA;EACA,sBAAA;EACA,cAAA;;AAbF,KAgBC,EAAC;EACA,mBAAA;EACA,YAAA;;AAlBF,KAqBC,EAAC;EACA,gBAAA;;AAKF;EACC,kBAAA;;AAGD,cAAc;AAAQ,aAAa;AAAQ,YAAY;EACtD,sBAAA;;AAGD;AAAgB;AAAe;EAC9B,sBAAA;;AAGD;EACC,2BAAA;;AAID,KAAK;EACJ,yBAAA;;AAID,QAAQ;EACP,4BAA4B,wBAA5B;EACA,gBAAA;;AAID,UAAW;EACV,gBAAA;EACA,gBAAA;EACA,kBAAA;EACA,2CAAA;EACA,aAAA;EACA,YAAA;;AAGD,UAAW,MAAK;EACf,UAAA","file":"@layout_popup.css"}
|
{"version":3,"sources":["@layout_popup.less"],"names":[],"mappings":";AACA;EACC,WAAA;;AAGD;EACC,aAAA;;AAGD;EACC,qBAAA;;AAGD,CAAC;AAAW,CAAC,SAAS;AAAQ,CAAC,SAAS;AAAS,IAAI;EACpD,WAAA;;AAGD,CAAC;AAAU,IAAI;AAAU,IAAI;EAC5B,cAAA;;AAGD,IAAI;AAAO,KAAK;AAAO,CAAC;EACvB,sBAAA;;AAGD,CAAC;EACA,iBAAA;;AAGD,IAAI;AAAM,GAAG;EACZ,cAAA;;AAGD,IAAI;EACH,cAAA;;AAGD,GAAG,IAAI;EACN,mBAAmB,8CAAnB;;AAGD;EACC,uBAAA;;AAGD,MAAM;EACL,sBAAA;;AAGD,MAAM;EACL,sBAAA;;AAGD,MAAM;EACL,sBAAA;;AAGD,MAAO;AAAI,MAAO;EACjB,gBAAA;;AAGD,CAAC;AAAU,GAAG;EACb,yBAAA;EACA,kBAAA;EACA,mBAAA;EACA,qBAAA;;AAGD,CAAC,QAAS;AAAI,GAAG,QAAS;EACzB,6BAAA;;AAGD;EACC,mBAAA;EACA,2BAAA;EACA,gBAAA;EACA,uBAAA;;AAGD,GAAG;AAAS,CAAC;EACZ,eAAA;;;AAID,GAAG;EACF,UAAA;;AAGD,GAAG;EACF,YAAA;;AAGD,GAAG;EACF,UAAA;;AAGD,GAAG;EACF,WAAA;;;AAID,MAAM;EACL,cAAA;;;AAID;EACC,kBAAA;EACA,UAAA;EACA,UAAA;EACA,mBAAA;EACA,kBAAA;EACA,UAAA;;AAGD,mBAAqC;EACpC;IACC,SAAA;;;AAIF,KAAK;EACJ,SAAA;;AAGD,KAAK;EACJ,UAAA;;AAGD,mBAAqC;EACpC,KAAK;IACJ,SAAA;;;AAIF,KAAM,MAAM,GAAE;EACb,WAAA;;AAGD,KAAM,MAAM,GAAE;EACb,WAAA;;AAGD,KAAM,MAAM;EACX,mBAAA;;AAGD,KAAM,GAAE;EACP,8BAAA;;AAGD,KAAM,MAAM,GAAE;EACb,mBAAA;;AAGD,KAAM,MAAM,GAAE;EACb,sBAAA;;AAGD,KAAM,MAAM,GAAE,aAAc;EAC3B,mBAAA;;AAGD,KAAM,MAAM,GAAG;EACd,mBAAA;EACA,kBAAA;EACA,gBAAA;;AAGD,KAAM;EACL,mBAAA;EACA,iBAAA;;AAGD,KAAM,GAAG;EACR,gBAAA;;AAGD,KAAM,GAAG,KAAI;EACZ,cAAA;;AAGD,KAAM,GAAG;EACR,gBAAA;EACA,0BAAA;EACA,UAAA;;AAGD,KAAM,GAAG,EAAC;EACT,SAAS,GAAT;;AAGD,KAAM,GAAG,EAAC;EACT,SAAS,GAAT;;AAGD,KAAM;EACL,mBAAA;;AAGD,KAAM,GAAG,KAAI;EACZ,gBAAA;;AAGD,KAAM,QAAO;EACZ,gBAAA;EACA,cAAA;EACA,gBAAA;;;AAID,KAAK;EACJ,gBAAA;;AAGD,KAAK,KAAK;EACT,UAAA;EACA,WAAA;;;AAID;EACC,wBAAA;;;AAID,iBAAkB;EACjB,gBAAA;;AAGD,iBAAkB,MAAK;EACtB,UAAA;;AAGD,iBAAkB,MAAM;EACvB,2BAAA;;AAGD,MAAM;EACL,sBAAA;;;AAID,mBAAqC;EACpC,OAAO,IAAI;IACV,sBAAA;;;;AAKF,KAAK;EACJ,0BAAA;;AAGD,KAAK;EACJ,cAAA;;;AAOD,WAAY,MAAK;EAChB,wBAAA;EACA,2BAAA;;AAGD,WAAY;EACX,wBAAA;EACA,2BAAA;;AAGD,YAAa,MAAK;EACjB,wBAAA;EACA,2BAAA;;AAGD,YAAa,MAAK,KAAM;EACvB,kBAAA;;AAGD,YAAa;EACZ,wBAAA;;AAGD,KAAM;EACL,aAAA;;;AAID,IAAI;AAAQ,GAAG;EACd,cAAA;;AAGD,GAAG;EACF,8BAAA;;;AAID,QAAS;EACR,WAAA;EACA,kBAAA;;;AAID,SAAU,MAAM;AAAG,SAAU;EAC5B,gBAAA;;;AAID;EACC,eAAA;EAEA,2BAAA;;AAHD,KAKC;EACC,qBAAA;EACA,mBAAA;EACA,WAAA;EACA,iBAAA;EACA,SAAA;EACA,gBAAA;EACA,sBAAA;EACA,cAAA;;AAbF,KAgBC,EAAC;EACA,mBAAA;EACA,YAAA;;AAlBF,KAqBC,EAAC;EACA,gBAAA;;AAKF;EACC,kBAAA;;AAGD,cAAc;AAAQ,aAAa;AAAQ,YAAY;EACtD,sBAAA;;AAGD;AAAgB;AAAe;EAC9B,sBAAA;;AAGD;EACC,2BAAA;;AAID,KAAK;EACJ,yBAAA;;AAID,QAAQ;EACP,4BAA4B,wBAA5B;EACA,gBAAA;;AAID,UAAW;EACV,gBAAA;EACA,gBAAA;EACA,kBAAA;EACA,2CAAA;EACA,aAAA;EACA,YAAA;;AAGD,UAAW,MAAK;EACf,UAAA","file":"@layout_popup.css"}
|
||||||
@@ -63,6 +63,7 @@ p.comment, div.comment {
|
|||||||
color: rgba(0, 0, 0, 0.4);
|
color: rgba(0, 0, 0, 0.4);
|
||||||
padding-top: 0.4em;
|
padding-top: 0.4em;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.comment em, div.comment em {
|
p.comment em, div.comment em {
|
||||||
|
|||||||
@@ -47,27 +47,30 @@
|
|||||||
<tr v-if="node.records.length > 0">
|
<tr v-if="node.records.length > 0">
|
||||||
<td>DNS记录</td>
|
<td>DNS记录</td>
|
||||||
<td>
|
<td>
|
||||||
<table class="ui table celled">
|
<div :style="{opacity: dnsIsExcludingLnNode ? 0.5 : 1.0}">
|
||||||
<thead class="full-width">
|
<table class="ui table celled">
|
||||||
<tr>
|
<thead class="full-width">
|
||||||
<th>记录名</th>
|
<tr>
|
||||||
<th>记录类型</th>
|
<th>记录名</th>
|
||||||
<th>线路</th>
|
<th>记录类型</th>
|
||||||
<th>记录值</th>
|
<th>线路</th>
|
||||||
</tr>
|
<th>记录值</th>
|
||||||
</thead>
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
<tr v-for="record in node.records">
|
<tr v-for="record in node.records">
|
||||||
<td>{{record.name}}</td>
|
<td>{{record.name}}</td>
|
||||||
<td>{{record.type}}</td>
|
<td>{{record.type}}</td>
|
||||||
<td>
|
<td>
|
||||||
<span v-if="record.route.length > 0">{{record.route}}</span>
|
<span v-if="record.route.length > 0">{{record.route}}</span>
|
||||||
<span v-else class="disabled">默认</span>
|
<span v-else class="disabled">默认</span>
|
||||||
</td>
|
</td>
|
||||||
<td>{{record.value}}</td>
|
<td>{{record.value}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<p class="comment">通过设置A记录可以将集群上的服务请求转发到不同线路的节点上。</p>
|
<p class="comment" v-if="!dnsIsExcludingLnNode">通过设置A记录可以将集群上的服务请求转发到不同线路的节点上。</p>
|
||||||
|
</div>
|
||||||
|
<p class="comment" v-if="dnsIsExcludingLnNode"><span class="red">当前集群DNS已设置不解析Ln节点,所以当前节点不会加入DNS解析;如需加入,请修改"集群设置" -- "DNS设置" -- "更多选项" -- "包含Ln节点"。</span></p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -88,6 +91,10 @@
|
|||||||
<td>级别</td>
|
<td>级别</td>
|
||||||
<td>
|
<td>
|
||||||
<span :class="{blue: node.levelInfo.code > 1}">{{node.levelInfo.name}}</span>
|
<span :class="{blue: node.levelInfo.code > 1}">{{node.levelInfo.name}}</span>
|
||||||
|
<span v-if="node.level > 1 && node.lnAddrs != null && node.lnAddrs.length > 0">
|
||||||
|
<span v-for="lnAddr in node.lnAddrs" class="ui label tiny basic">{{lnAddr}}</span>
|
||||||
|
</span>
|
||||||
|
<p class="comment" v-if="node.level > 1 && node.lnAddrs != null && node.lnAddrs.length > 0">指定了Ln节点访问地址。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -48,10 +48,17 @@
|
|||||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tbody v-show="moreOptionsVisible">
|
<tbody v-show="moreOptionsVisible">
|
||||||
<tr v-if="teaIsPlus && canUpdateLevel">
|
<tr v-show="teaIsPlus && canUpdateLevel">
|
||||||
<td>级别</td>
|
<td>级别</td>
|
||||||
<td>
|
<td>
|
||||||
<node-level-selector :v-node-level="node.level"></node-level-selector>
|
<node-level-selector :v-node-level="node.level" @change="changeLevel"></node-level-selector>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-show="teaIsPlus && canUpdateLevel && nodeLevel > 1">
|
||||||
|
<td>L2级别访问地址</td>
|
||||||
|
<td>
|
||||||
|
<values-box name="lnAddrs" :v-values="node.lnAddrs" placeholder="IP地址"></values-box>
|
||||||
|
<p class="comment">如果不为空,边缘节点访问当前L2节点时将会使用这些IP地址;如果没有设置,将会使用当前节点已经填写的IP地址。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -26,4 +26,12 @@ Tea.context(function () {
|
|||||||
this.updateClusters = function () {
|
this.updateClusters = function () {
|
||||||
this.showClustersBox = !this.showClustersBox
|
this.showClustersBox = !this.showClustersBox
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 级别相关
|
||||||
|
*/
|
||||||
|
this.nodeLevel = this.node.level
|
||||||
|
this.changeLevel = function (level) {
|
||||||
|
this.nodeLevel = level
|
||||||
|
}
|
||||||
})
|
})
|
||||||
@@ -52,6 +52,13 @@
|
|||||||
<p class="comment">选中后,表示允许使用CNAME直接访问网站服务;如果取消选中,则表示CNAME只作为DNS解析记录使用。</p>
|
<p class="comment">选中后,表示允许使用CNAME直接访问网站服务;如果取消选中,则表示CNAME只作为DNS解析记录使用。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr v-show="teaIsPlus">
|
||||||
|
<td>包含Ln节点</td>
|
||||||
|
<td>
|
||||||
|
<checkbox name="includingLnNodes" v-model="includingLnNodes"></checkbox>
|
||||||
|
<p class="comment">选中后,表示域名解析中包含L2及以上级别节点。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>记录TTL</td>
|
<td>记录TTL</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -52,6 +52,7 @@
|
|||||||
<second-menu v-if="logs.length > 0">
|
<second-menu v-if="logs.length > 0">
|
||||||
<a href="" class="item" @click.prevent="updatePageRead()">[本页已读]</a>
|
<a href="" class="item" @click.prevent="updatePageRead()">[本页已读]</a>
|
||||||
<a href="" class="item" @click.prevent="updateAllRead()">[全部已读]</a>
|
<a href="" class="item" @click.prevent="updateAllRead()">[全部已读]</a>
|
||||||
|
<a href="" class="item" @click.prevent="updateNodeRead(firstUnreadNode.id)" v-if="firstUnreadNode != null">["{{firstUnreadNode.name}}"节点已读]</a>
|
||||||
</second-menu>
|
</second-menu>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,16 @@ Tea.context(function () {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updateNodeRead = function (nodeId) {
|
||||||
|
this.$post(".readLogs")
|
||||||
|
.params({
|
||||||
|
nodeId: nodeId
|
||||||
|
})
|
||||||
|
.success(function () {
|
||||||
|
teaweb.reload()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
this.updateAllRead = function () {
|
this.updateAllRead = function () {
|
||||||
this.$post(".readAllLogs")
|
this.$post(".readAllLogs")
|
||||||
.params({})
|
.params({})
|
||||||
|
|||||||
@@ -55,6 +55,20 @@
|
|||||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tbody v-show="moreOptionsVisible">
|
<tbody v-show="moreOptionsVisible">
|
||||||
|
<tr>
|
||||||
|
<td>允许通过CNAME访问网站服务</td>
|
||||||
|
<td>
|
||||||
|
<checkbox name="cnameAsDomain" v-model="cnameAsDomain"></checkbox>
|
||||||
|
<p class="comment">选中后,表示允许使用CNAME直接访问网站服务;如果取消选中,则表示CNAME只作为DNS解析记录使用。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-show="teaIsPlus">
|
||||||
|
<td>包含Ln节点</td>
|
||||||
|
<td>
|
||||||
|
<checkbox name="includingLnNodes" v-model="includingLnNodes"></checkbox>
|
||||||
|
<p class="comment">选中后,表示域名解析中包含L2及以上级别节点。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>记录TTL</td>
|
<td>记录TTL</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -43,14 +43,14 @@
|
|||||||
<td class="color-border">缓存文件句柄缓存</td>
|
<td class="color-border">缓存文件句柄缓存</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="fileOpenFileCacheMax" maxlength="6" value="0" style="width: 10em"/>
|
<input type="text" name="fileOpenFileCacheMax" maxlength="6" value="0" style="width: 10em"/>
|
||||||
<p class="comment">保持在内存中的缓存文件句柄的数量,提升缓存文件打开速度,建议数量不超过缓存文件数量的十分之一。</p>
|
<p class="comment"><pro-warning-label></pro-warning-label>保持在内存中的缓存文件句柄的数量,提升缓存文件打开速度,建议数量不超过缓存文件数量的十分之一。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-show="teaIsPlus">
|
<tr v-show="teaIsPlus">
|
||||||
<td class="color-border">开启Sendfile</td>
|
<td class="color-border">开启Sendfile</td>
|
||||||
<td>
|
<td>
|
||||||
<checkbox name="fileEnableSendfile"></checkbox>
|
<checkbox name="fileEnableSendfile"></checkbox>
|
||||||
<p class="comment"><plus-label></plus-label>使用sendfile提升发送缓存文件的效率。</p>
|
<p class="comment"><pro-warning-label></pro-warning-label><plus-label></plus-label>使用sendfile提升发送缓存文件的效率。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -52,14 +52,14 @@
|
|||||||
<td class="color-border">缓存文件句柄缓存</td>
|
<td class="color-border">缓存文件句柄缓存</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="fileOpenFileCacheMax" v-model="fileOpenFileCacheMax" maxlength="6" value="0" style="width: 10em"/>
|
<input type="text" name="fileOpenFileCacheMax" v-model="fileOpenFileCacheMax" maxlength="6" value="0" style="width: 10em"/>
|
||||||
<p class="comment">保持在内存中的缓存文件句柄的数量,提升缓存文件打开速度,建议数量不超过缓存文件数量的十分之一。</p>
|
<p class="comment"><pro-warning-label></pro-warning-label>保持在内存中的缓存文件句柄的数量,提升缓存文件打开速度,建议数量不超过缓存文件数量的十分之一。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-show="teaIsPlus">
|
<tr v-show="teaIsPlus">
|
||||||
<td class="color-border">开启Sendfile</td>
|
<td class="color-border">开启Sendfile</td>
|
||||||
<td>
|
<td>
|
||||||
<checkbox name="fileEnableSendfile" v-model="cachePolicy.options.enableSendfile"></checkbox>
|
<checkbox name="fileEnableSendfile" v-model="cachePolicy.options.enableSendfile"></checkbox>
|
||||||
<p class="comment"><plus-label></plus-label>使用sendfile提升发送缓存文件的效率。</p>
|
<p class="comment"><pro-warning-label></pro-warning-label><plus-label></plus-label>使用sendfile提升发送缓存文件的效率。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
<th>部署集群</th>
|
<th>部署集群</th>
|
||||||
<th>域名</th>
|
<th>域名</th>
|
||||||
<th>端口</th>
|
<th>端口</th>
|
||||||
<th class="center" style="width: 8em">下行带宽<tip-icon content="最近5分钟平均带宽,每5分钟更新一次"></tip-icon><sort-arrow name="trafficOutOrder"></sort-arrow></th>
|
<th class="center" style="width: 8em">下行带宽<tip-icon content="最近5分钟峰值带宽,每5分钟更新一次"></tip-icon><sort-arrow name="trafficOutOrder"></sort-arrow></th>
|
||||||
<th class="two wide center">状态</th>
|
<th class="two wide center">状态</th>
|
||||||
<th class="two op">操作</th>
|
<th class="two op">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
{$template "/datepicker"}
|
{$template "/datepicker"}
|
||||||
|
|
||||||
<first-menu>
|
<first-menu>
|
||||||
<menu-item :href="path + '?clusterId=' + clusterId + '&nodeId=' + nodeId + '&serverId=' + serverId + '&day=' + day + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" :active="hasError == 0 && hasWAF == 0">所有日志</menu-item>
|
<menu-item :href="path + '?' + query('')" :active="hasError == 0 && hasWAF == 0">所有日志</menu-item>
|
||||||
<menu-item :href="path + '?clusterId=' + clusterId + '&nodeId=' + nodeId + '&serverId=' + serverId + '&day=' + day + '&hasError=1' + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" :active="hasError > 0">错误日志</menu-item>
|
<menu-item :href="path + '?' + query('hasError=1')" :active="hasError > 0">错误日志</menu-item>
|
||||||
<menu-item :href="path + '?clusterId=' + clusterId + '&nodeId=' + nodeId + '&serverId=' + serverId + '&day=' + day + '&hasWAF=1' + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" :active="hasWAF > 0">WAF日志</menu-item>
|
<menu-item :href="path + '?' + query('hasWAF=1')" :active="hasWAF > 0">WAF日志</menu-item>
|
||||||
<span class="item disabled">|</span>
|
<span class="item disabled">|</span>
|
||||||
<menu-item :href="'/servers/logs/settings'" code="settings">设置</menu-item>
|
<menu-item :href="'/servers/logs/settings'" code="settings">设置</menu-item>
|
||||||
</first-menu>
|
</first-menu>
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
</http-access-log-search-box>
|
</http-access-log-search-box>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<http-access-log-partitions-box :v-partition="partition" :v-day="day"></http-access-log-partitions-box>
|
<http-access-log-partitions-box :v-partition="partition" :v-day="day" :v-query="currentQuery"></http-access-log-partitions-box>
|
||||||
|
|
||||||
<warning-message v-if="isSlowQuery">看起来你的访问日志查询非常慢({{slowQueryCost}}s),建议<span v-if="domain.length == 0"> 1)指定具体域名查询;2)</span>通过添加新的 <a href="/db">[日志节点]</a> 来分散存储访问日志。</warning-message>
|
<warning-message v-if="isSlowQuery">看起来你的访问日志查询非常慢({{slowQueryCost}}s),建议<span v-if="domain.length == 0"> 1)指定具体域名查询;2)</span>通过添加新的 <a href="/db">[日志节点]</a> 来分散存储访问日志。</warning-message>
|
||||||
|
|
||||||
@@ -43,10 +43,10 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div v-if="accessLogs.length > 0">
|
<div v-if="accessLogs.length > 0">
|
||||||
<a :href="path + '?clusterId=' + clusterId + '&nodeId=' + nodeId + '&serverId=' + serverId + '&requestId=' + lastRequestId + '&day=' + day + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize + '&partition=' + partition" v-if="hasPrev">上一页</a>
|
<a :href="path + '?' + query('requestId=' + lastRequestId + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&partition=' + partition)" v-if="hasPrev">上一页</a>
|
||||||
<span v-else class="disabled">上一页</span>
|
<span v-else class="disabled">上一页</span>
|
||||||
<span class="disabled"> | </span>
|
<span class="disabled"> | </span>
|
||||||
<a :href="path + '?clusterId=' + clusterId + '&nodeId=' + nodeId + '&serverId=' + serverId + '&requestId=' + nextRequestId + '&day=' + day + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize + '&partition=' + partition" v-if="hasMore">下一页</a>
|
<a :href="path + '?' + query('requestId=' + nextRequestId + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&partition=' + partition)" v-if="hasMore">下一页</a>
|
||||||
<span v-else class="disabled">下一页</span>
|
<span v-else class="disabled">下一页</span>
|
||||||
|
|
||||||
<page-size-selector></page-size-selector>
|
<page-size-selector></page-size-selector>
|
||||||
|
|||||||
@@ -19,4 +19,60 @@ Tea.context(function () {
|
|||||||
accessLog.wafInfo = null
|
accessLog.wafInfo = null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.query = function (args) {
|
||||||
|
// 初始化时页面尚未设置Vue变量,所以使用全局的变量获取
|
||||||
|
let that = TEA.ACTION.data
|
||||||
|
|
||||||
|
if (that.clusterId == null) {
|
||||||
|
that.clusterId = 0
|
||||||
|
}
|
||||||
|
if (that.nodeId == null) {
|
||||||
|
that.nodeId = 0
|
||||||
|
}
|
||||||
|
if (that.serverId == null) {
|
||||||
|
that.serverId = 0
|
||||||
|
}
|
||||||
|
if (that.day == null) {
|
||||||
|
that.day = ""
|
||||||
|
}
|
||||||
|
if (that.keyword == null) {
|
||||||
|
that.keyword = ""
|
||||||
|
}
|
||||||
|
if (that.ip == null) {
|
||||||
|
that.ip = ""
|
||||||
|
}
|
||||||
|
if (that.domain == null) {
|
||||||
|
that.domain = ""
|
||||||
|
}
|
||||||
|
if (that.hour == null) {
|
||||||
|
that.hour = ""
|
||||||
|
}
|
||||||
|
if (that.pageSize == null) {
|
||||||
|
that.pageSize = 0
|
||||||
|
}
|
||||||
|
let query = 'clusterId=' + that.clusterId + '&nodeId=' + that.nodeId + '&serverId=' + that.serverId + '&day=' + that.day + '&keyword=' + encodeURIComponent(that.keyword) + '&ip=' + that.ip + '&domain=' + that.domain + '&hour=' + that.hour + '&pageSize=' + that.pageSize
|
||||||
|
|
||||||
|
if (args != null && args.length > 0) {
|
||||||
|
query += "&" + args
|
||||||
|
}
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
this.allQuery = function () {
|
||||||
|
if (this.query == null) {
|
||||||
|
// 尚未初始化完成
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let query = this.query()
|
||||||
|
if (this.hasError == 1) {
|
||||||
|
query += "&hasError=1"
|
||||||
|
}
|
||||||
|
if (this.hasWAF == 1) {
|
||||||
|
query += "&hasWAF=1"
|
||||||
|
}
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentQuery = this.allQuery()
|
||||||
})
|
})
|
||||||
@@ -15,9 +15,9 @@
|
|||||||
{$template "/left_menu_with_menu"}
|
{$template "/left_menu_with_menu"}
|
||||||
<div class="right-box with-menu">
|
<div class="right-box with-menu">
|
||||||
<first-menu>
|
<first-menu>
|
||||||
<menu-item :href="path + '?serverId=' + serverId + '&day=' + day + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" :active="hasError == 0 && hasWAF == 0">所有日志</menu-item>
|
<menu-item :href="path + '?' + query()" :active="hasError == 0 && hasWAF == 0">所有日志</menu-item>
|
||||||
<menu-item :href="path + '?serverId=' + serverId + '&day=' + day + '&hasError=1' + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" :active="hasError > 0">错误日志</menu-item>
|
<menu-item :href="path + '?' + query('hasError=1')" :active="hasError > 0">错误日志</menu-item>
|
||||||
<menu-item :href="path + '?serverId=' + serverId + '&day=' + day + '&hasWAF=1' + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" :active="hasWAF > 0">WAF日志</menu-item>
|
<menu-item :href="path + '?' + query('hasWAF=1')" :active="hasWAF > 0">WAF日志</menu-item>
|
||||||
</first-menu>
|
</first-menu>
|
||||||
|
|
||||||
<form method="get" class="ui form small" :action="path">
|
<form method="get" class="ui form small" :action="path">
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<!-- 分区 -->
|
<!-- 分区 -->
|
||||||
<http-access-log-partitions-box :v-day="day" :v-partition="partition"></http-access-log-partitions-box>
|
<http-access-log-partitions-box :v-day="day" :v-partition="partition" :v-query="currentQuery"></http-access-log-partitions-box>
|
||||||
|
|
||||||
<p class="comment" v-if="accessLogs.length == 0">暂时还没有访问日志。</p>
|
<p class="comment" v-if="accessLogs.length == 0">暂时还没有访问日志。</p>
|
||||||
|
|
||||||
@@ -50,10 +50,10 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div v-if="accessLogs.length > 0">
|
<div v-if="accessLogs.length > 0">
|
||||||
<a :href="path + '?serverId=' + serverId + '&requestId=' + lastRequestId + '&day=' + day + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize + '&partition=' + partition" v-if="hasPrev">上一页</a>
|
<a :href="path + '?' + query('requestId=' + lastRequestId + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&partition=' + partition)" v-if="hasPrev">上一页</a>
|
||||||
<span v-else class="disabled">上一页</span>
|
<span v-else class="disabled">上一页</span>
|
||||||
<span class="disabled"> | </span>
|
<span class="disabled"> | </span>
|
||||||
<a :href="path + '?serverId=' + serverId + '&requestId=' + nextRequestId + '&day=' + day + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize + '&partition=' + partition" v-if="hasMore">下一页</a>
|
<a :href="path + '?' + query('requestId=' + nextRequestId + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&partition=' + partition)" v-if="hasMore">下一页</a>
|
||||||
<span v-else class="disabled">下一页</span>
|
<span v-else class="disabled">下一页</span>
|
||||||
<page-size-selector></page-size-selector>
|
<page-size-selector></page-size-selector>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,22 +1,71 @@
|
|||||||
Tea.context(function () {
|
Tea.context(function () {
|
||||||
this.$delay(function () {
|
this.$delay(function () {
|
||||||
let that = this
|
let that = this
|
||||||
teaweb.datepicker("day-input", function (day) {
|
teaweb.datepicker("day-input", function (day) {
|
||||||
that.day = day
|
that.day = day
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
let that = this
|
let that = this
|
||||||
this.accessLogs.forEach(function (accessLog) {
|
this.accessLogs.forEach(function (accessLog) {
|
||||||
if (typeof (that.regions[accessLog.remoteAddr]) == "string") {
|
if (typeof (that.regions[accessLog.remoteAddr]) == "string") {
|
||||||
accessLog.region = that.regions[accessLog.remoteAddr]
|
accessLog.region = that.regions[accessLog.remoteAddr]
|
||||||
} else {
|
} else {
|
||||||
accessLog.region = ""
|
accessLog.region = ""
|
||||||
}
|
}
|
||||||
if (accessLog.firewallRuleSetId > 0 && typeof (that.wafInfos[accessLog.firewallRuleSetId]) == "object") {
|
if (accessLog.firewallRuleSetId > 0 && typeof (that.wafInfos[accessLog.firewallRuleSetId]) == "object") {
|
||||||
accessLog.wafInfo = that.wafInfos[accessLog.firewallRuleSetId]
|
accessLog.wafInfo = that.wafInfos[accessLog.firewallRuleSetId]
|
||||||
} else {
|
} else {
|
||||||
accessLog.wafInfo = null
|
accessLog.wafInfo = null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.query = function (args) {
|
||||||
|
// 初始化时页面尚未设置Vue变量,所以使用全局的变量获取
|
||||||
|
let that = TEA.ACTION.data
|
||||||
|
|
||||||
|
if (that.serverId == null) {
|
||||||
|
that.serverId = 0
|
||||||
|
}
|
||||||
|
if (that.keyword == null) {
|
||||||
|
that.keyword = ""
|
||||||
|
}
|
||||||
|
if (that.ip == null) {
|
||||||
|
that.ip = ""
|
||||||
|
}
|
||||||
|
if (that.domain == null) {
|
||||||
|
that.domain = ""
|
||||||
|
}
|
||||||
|
if (that.pageSize == null) {
|
||||||
|
that.pageSize = ""
|
||||||
|
}
|
||||||
|
if (that.day == null) {
|
||||||
|
that.day = ""
|
||||||
|
}
|
||||||
|
if (that.hour == null) {
|
||||||
|
that.hour = ""
|
||||||
|
}
|
||||||
|
let query = 'serverId=' + that.serverId + '&day=' + that.day + '&keyword=' + encodeURIComponent(that.keyword) + '&ip=' + that.ip + '&domain=' + that.domain + '&hour=' + that.hour + '&pageSize=' + that.pageSize
|
||||||
|
if (args != null && args.length > 0) {
|
||||||
|
query += "&" + args
|
||||||
|
}
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
this.allQuery = function () {
|
||||||
|
if (this.query == null) {
|
||||||
|
// 尚未初始化完成
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let query = this.query()
|
||||||
|
if (this.hasError == 1) {
|
||||||
|
query += "&hasError=1"
|
||||||
|
}
|
||||||
|
if (this.hasWAF == 1) {
|
||||||
|
query += "&hasWAF=1"
|
||||||
|
}
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentQuery = this.allQuery()
|
||||||
})
|
})
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user