mirror of
				https://github.com/TeaOSLab/EdgeAdmin.git
				synced 2025-11-04 05:00:25 +08:00 
			
		
		
		
	实现缓存策略的部分功能
This commit is contained in:
		@@ -1,4 +1,4 @@
 | 
			
		||||
rpc:
 | 
			
		||||
  endpoints: [ "127.0.0.1:8003" ]
 | 
			
		||||
  endpoints: [ "http://127.0.0.1:8003" ]
 | 
			
		||||
  nodeId: ""
 | 
			
		||||
  secret: ""
 | 
			
		||||
@@ -13,6 +13,7 @@ import (
 | 
			
		||||
	"github.com/iwind/TeaGo/rands"
 | 
			
		||||
	"google.golang.org/grpc"
 | 
			
		||||
	"google.golang.org/grpc/metadata"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -30,7 +31,19 @@ func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) {
 | 
			
		||||
 | 
			
		||||
	conns := []*grpc.ClientConn{}
 | 
			
		||||
	for _, endpoint := range apiConfig.RPC.Endpoints {
 | 
			
		||||
		conn, err := grpc.Dial(endpoint, grpc.WithInsecure())
 | 
			
		||||
		u, err := url.Parse(endpoint)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errors.New("parse endpoint failed: " + err.Error())
 | 
			
		||||
		}
 | 
			
		||||
		var conn *grpc.ClientConn
 | 
			
		||||
		if u.Scheme == "http" {
 | 
			
		||||
			conn, err = grpc.Dial(u.Host, grpc.WithInsecure())
 | 
			
		||||
		} else if u.Scheme == "https" {
 | 
			
		||||
			// TODO 暂不支持HTTPS
 | 
			
		||||
			conn, err = grpc.Dial(u.Host)
 | 
			
		||||
		} else {
 | 
			
		||||
			return nil, errors.New("parse endpoint failed: invalid scheme '" + u.Scheme + "'")
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
package rpc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/configs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	_ "github.com/iwind/TeaGo/bootstrap"
 | 
			
		||||
	stringutil "github.com/iwind/TeaGo/utils/string"
 | 
			
		||||
	"testing"
 | 
			
		||||
@@ -31,3 +31,66 @@ func TestRPCClient_NodeRPC(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
	t.Log(resp)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRPC_Dial_HTTP(t *testing.T) {
 | 
			
		||||
	client, err := NewRPCClient(&configs.APIConfig{
 | 
			
		||||
		RPC: struct {
 | 
			
		||||
			Endpoints []string `yaml:"endpoints"`
 | 
			
		||||
		}{
 | 
			
		||||
			Endpoints: []string{"127.0.0.1:8003"},
 | 
			
		||||
		},
 | 
			
		||||
		NodeId: "a7e55782dab39bce0901058a1e14a0e6",
 | 
			
		||||
		Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := client.NodeRPC().FindEnabledNode(client.Context(1), &pb.FindEnabledNodeRequest{NodeId: 4})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	t.Log(resp.Node)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRPC_Dial_HTTP_2(t *testing.T) {
 | 
			
		||||
	client, err := NewRPCClient(&configs.APIConfig{
 | 
			
		||||
		RPC: struct {
 | 
			
		||||
			Endpoints []string `yaml:"endpoints"`
 | 
			
		||||
		}{
 | 
			
		||||
			Endpoints: []string{"http://127.0.0.1:8003"},
 | 
			
		||||
		},
 | 
			
		||||
		NodeId: "a7e55782dab39bce0901058a1e14a0e6",
 | 
			
		||||
		Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := client.NodeRPC().FindEnabledNode(client.Context(1), &pb.FindEnabledNodeRequest{NodeId: 4})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	t.Log(resp.Node)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRPC_Dial_HTTPS(t *testing.T) {
 | 
			
		||||
	client, err := NewRPCClient(&configs.APIConfig{
 | 
			
		||||
		RPC: struct {
 | 
			
		||||
			Endpoints []string `yaml:"endpoints"`
 | 
			
		||||
		}{
 | 
			
		||||
			Endpoints: []string{"https://127.0.0.1:8004"},
 | 
			
		||||
		},
 | 
			
		||||
		NodeId: "a7e55782dab39bce0901058a1e14a0e6",
 | 
			
		||||
		Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := client.NodeRPC().FindEnabledNode(client.Context(1), &pb.FindEnabledNodeRequest{NodeId: 4})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	t.Log(resp.Node)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -40,8 +40,7 @@ func (this *IndexAction) RunGet(params struct{}) {
 | 
			
		||||
				"id":          node.Id,
 | 
			
		||||
				"isOn":        node.IsOn,
 | 
			
		||||
				"name":        node.Name,
 | 
			
		||||
				"host": node.Host,
 | 
			
		||||
				"port": node.Port,
 | 
			
		||||
				"accessAddrs": node.AccessAddrs,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,11 @@
 | 
			
		||||
package node
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -20,26 +23,112 @@ func (this *CreateAction) RunGet(params struct{}) {
 | 
			
		||||
 | 
			
		||||
func (this *CreateAction) RunPost(params struct {
 | 
			
		||||
	Name            string
 | 
			
		||||
	Host        string
 | 
			
		||||
	Port        int
 | 
			
		||||
	Description     string
 | 
			
		||||
	ListensJSON     []byte
 | 
			
		||||
	CertIdsJSON     []byte
 | 
			
		||||
	AccessAddrsJSON []byte
 | 
			
		||||
	IsOn            bool
 | 
			
		||||
 | 
			
		||||
	Must *actions.Must
 | 
			
		||||
}) {
 | 
			
		||||
	params.Must.
 | 
			
		||||
		Field("name", params.Name).
 | 
			
		||||
		Require("请输入API节点").
 | 
			
		||||
		Field("host", params.Host).
 | 
			
		||||
		Require("请输入主机地址").
 | 
			
		||||
		Field("port", params.Port).
 | 
			
		||||
		Gt(0, "端口不能小于1").
 | 
			
		||||
		Lte(65535, "端口不能大于65535")
 | 
			
		||||
		Require("请输入API节点名称")
 | 
			
		||||
 | 
			
		||||
	_, err := this.RPC().APINodeRPC().CreateAPINode(this.AdminContext(), &pb.CreateAPINodeRequest{
 | 
			
		||||
	httpConfig := &serverconfigs.HTTPProtocolConfig{}
 | 
			
		||||
	httpsConfig := &serverconfigs.HTTPSProtocolConfig{}
 | 
			
		||||
 | 
			
		||||
	// 监听地址
 | 
			
		||||
	listens := []*serverconfigs.NetworkAddressConfig{}
 | 
			
		||||
	err := json.Unmarshal(params.ListensJSON, &listens)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if len(listens) == 0 {
 | 
			
		||||
		this.Fail("请添加至少一个进程监听地址")
 | 
			
		||||
	}
 | 
			
		||||
	for _, addr := range listens {
 | 
			
		||||
		if addr.Protocol.IsHTTPFamily() {
 | 
			
		||||
			httpConfig.IsOn = true
 | 
			
		||||
			httpConfig.Listen = append(httpConfig.Listen, addr)
 | 
			
		||||
		} else if addr.Protocol.IsHTTPSFamily() {
 | 
			
		||||
			httpsConfig.IsOn = true
 | 
			
		||||
			httpsConfig.Listen = append(httpsConfig.Listen, addr)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 证书
 | 
			
		||||
	certIds := []int64{}
 | 
			
		||||
	if len(params.CertIdsJSON) > 0 {
 | 
			
		||||
		err = json.Unmarshal(params.CertIdsJSON, &certIds)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			this.ErrorPage(err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if httpsConfig.IsOn && len(httpsConfig.Listen) > 0 && len(certIds) == 0 {
 | 
			
		||||
		this.Fail("请添加至少一个证书")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	certRefs := []*sslconfigs.SSLCertRef{}
 | 
			
		||||
	for _, certId := range certIds {
 | 
			
		||||
		certRefs = append(certRefs, &sslconfigs.SSLCertRef{
 | 
			
		||||
			IsOn:   true,
 | 
			
		||||
			CertId: certId,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	certRefsJSON, err := json.Marshal(certRefs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 创建策略
 | 
			
		||||
	if len(certIds) > 0 {
 | 
			
		||||
		sslPolicyCreateResp, err := this.RPC().SSLPolicyRPC().CreateSSLPolicy(this.AdminContext(), &pb.CreateSSLPolicyRequest{
 | 
			
		||||
			CertsJSON: certRefsJSON,
 | 
			
		||||
		})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			this.ErrorPage(err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		sslPolicyId := sslPolicyCreateResp.SslPolicyId
 | 
			
		||||
		httpsConfig.SSLPolicyRef = &sslconfigs.SSLPolicyRef{
 | 
			
		||||
			IsOn:        true,
 | 
			
		||||
			SSLPolicyId: sslPolicyId,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 访问地址
 | 
			
		||||
	accessAddrs := []*serverconfigs.NetworkAddressConfig{}
 | 
			
		||||
	err = json.Unmarshal(params.AccessAddrsJSON, &accessAddrs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if len(accessAddrs) == 0 {
 | 
			
		||||
		this.Fail("请添加至少一个外部访问地址")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	httpJSON, err := json.Marshal(httpConfig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	httpsJSON, err := json.Marshal(httpsConfig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = this.RPC().APINodeRPC().CreateAPINode(this.AdminContext(), &pb.CreateAPINodeRequest{
 | 
			
		||||
		Name:            params.Name,
 | 
			
		||||
		Description:     params.Description,
 | 
			
		||||
		Host:        params.Host,
 | 
			
		||||
		Port:        int32(params.Port),
 | 
			
		||||
		HttpJSON:        httpJSON,
 | 
			
		||||
		HttpsJSON:       httpsJSON,
 | 
			
		||||
		AccessAddrsJSON: params.AccessAddrsJSON,
 | 
			
		||||
		IsOn:            params.IsOn,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										44
									
								
								internal/web/actions/default/api/node/createAddrPopup.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								internal/web/actions/default/api/node/createAddrPopup.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
package node
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
	"net"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 添加地址
 | 
			
		||||
type CreateAddrPopupAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *CreateAddrPopupAction) Init() {
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *CreateAddrPopupAction) RunGet(params struct {
 | 
			
		||||
}) {
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *CreateAddrPopupAction) RunPost(params struct {
 | 
			
		||||
	Protocol string
 | 
			
		||||
	Addr     string
 | 
			
		||||
	Must     *actions.Must
 | 
			
		||||
}) {
 | 
			
		||||
	params.Must.
 | 
			
		||||
		Field("addr", params.Addr).
 | 
			
		||||
		Require("请输入访问地址")
 | 
			
		||||
	host, port, err := net.SplitHostPort(params.Addr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.FailField("addr", "错误的访问地址")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	addrConfig := &serverconfigs.NetworkAddressConfig{
 | 
			
		||||
		Protocol:  serverconfigs.Protocol(params.Protocol),
 | 
			
		||||
		Host:      host,
 | 
			
		||||
		PortRange: port,
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["addr"] = addrConfig
 | 
			
		||||
	this.Success()
 | 
			
		||||
}
 | 
			
		||||
@@ -2,8 +2,8 @@ package node
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
	"github.com/iwind/TeaGo/logs"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
@@ -48,8 +48,12 @@ func (this *Helper) BeforeAction(action *actions.ActionObject) (goNext bool) {
 | 
			
		||||
	// 顶部Tab栏
 | 
			
		||||
	selectedTabbar, _ := action.Data["mainTab"]
 | 
			
		||||
	tabbar := actionutils.NewTabbar()
 | 
			
		||||
	tabbar.Add("当前节点:"+node.Name, "", "/api", "left long alternate arrow", false)
 | 
			
		||||
	tabbar.Add("节点列表", "", "/api", "", false)
 | 
			
		||||
	tabbar.Add("设置", "", "/api/node/settings?nodeId="+nodeIdString, "setting", selectedTabbar == "setting")
 | 
			
		||||
	{
 | 
			
		||||
		m := tabbar.Add("当前节点:"+node.Name, "", "", "", false)
 | 
			
		||||
		m["right"] = true
 | 
			
		||||
	}
 | 
			
		||||
	actionutils.SetTabbar(action, tabbar)
 | 
			
		||||
 | 
			
		||||
	// 左侧菜单栏
 | 
			
		||||
 
 | 
			
		||||
@@ -9,12 +9,17 @@ func init() {
 | 
			
		||||
	TeaGo.BeforeStart(func(server *TeaGo.Server) {
 | 
			
		||||
		server.
 | 
			
		||||
			Helper(helpers.NewUserMustAuth()).
 | 
			
		||||
			Helper(NewHelper()).
 | 
			
		||||
			Prefix("/api/node").
 | 
			
		||||
 | 
			
		||||
			// 这里不受Helper的约束
 | 
			
		||||
			GetPost("/createAddrPopup", new(CreateAddrPopupAction)).
 | 
			
		||||
			GetPost("/updateAddrPopup", new(UpdateAddrPopupAction)).
 | 
			
		||||
 | 
			
		||||
			// 节点相关
 | 
			
		||||
			Helper(NewHelper()).
 | 
			
		||||
			GetPost("/settings", new(SettingsAction)).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
			EndAll()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,11 @@
 | 
			
		||||
package node
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
@@ -32,12 +35,69 @@ func (this *SettingsAction) RunGet(params struct {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	httpConfig := &serverconfigs.HTTPProtocolConfig{}
 | 
			
		||||
	if len(node.HttpJSON) > 0 {
 | 
			
		||||
		err = json.Unmarshal(node.HttpJSON, httpConfig)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			this.ErrorPage(err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	httpsConfig := &serverconfigs.HTTPSProtocolConfig{}
 | 
			
		||||
	if len(node.HttpsJSON) > 0 {
 | 
			
		||||
		err = json.Unmarshal(node.HttpsJSON, httpsConfig)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			this.ErrorPage(err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 监听地址
 | 
			
		||||
	listens := []*serverconfigs.NetworkAddressConfig{}
 | 
			
		||||
	listens = append(listens, httpConfig.Listen...)
 | 
			
		||||
	listens = append(listens, httpsConfig.Listen...)
 | 
			
		||||
 | 
			
		||||
	// 证书信息
 | 
			
		||||
	certs := []*sslconfigs.SSLCertConfig{}
 | 
			
		||||
	sslPolicyId := int64(0)
 | 
			
		||||
	if httpsConfig.SSLPolicyRef != nil && httpsConfig.SSLPolicyRef.SSLPolicyId > 0 {
 | 
			
		||||
		sslPolicyConfigResp, err := this.RPC().SSLPolicyRPC().FindEnabledSSLPolicyConfig(this.AdminContext(), &pb.FindEnabledSSLPolicyConfigRequest{SslPolicyId: httpsConfig.SSLPolicyRef.SSLPolicyId})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			this.ErrorPage(err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		sslPolicyConfigJSON := sslPolicyConfigResp.SslPolicyJSON
 | 
			
		||||
		if len(sslPolicyConfigJSON) > 0 {
 | 
			
		||||
			sslPolicyId = httpsConfig.SSLPolicyRef.SSLPolicyId
 | 
			
		||||
 | 
			
		||||
			sslPolicy := &sslconfigs.SSLPolicy{}
 | 
			
		||||
			err = json.Unmarshal(sslPolicyConfigJSON, sslPolicy)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				this.ErrorPage(err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			certs = sslPolicy.Certs
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	accessAddrs := []*serverconfigs.NetworkAddressConfig{}
 | 
			
		||||
	if len(node.AccessAddrsJSON) > 0 {
 | 
			
		||||
		err = json.Unmarshal(node.AccessAddrsJSON, &accessAddrs)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			this.ErrorPage(err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Data["node"] = maps.Map{
 | 
			
		||||
		"id":          node.Id,
 | 
			
		||||
		"name":        node.Name,
 | 
			
		||||
		"description": node.Description,
 | 
			
		||||
		"host":        node.Host,
 | 
			
		||||
		"port":        node.Port,
 | 
			
		||||
		"isOn":        node.IsOn,
 | 
			
		||||
		"listens":     listens,
 | 
			
		||||
		"certs":       certs,
 | 
			
		||||
		"sslPolicyId": sslPolicyId,
 | 
			
		||||
		"accessAddrs": accessAddrs,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
@@ -47,27 +107,126 @@ func (this *SettingsAction) RunGet(params struct {
 | 
			
		||||
func (this *SettingsAction) RunPost(params struct {
 | 
			
		||||
	NodeId          int64
 | 
			
		||||
	Name            string
 | 
			
		||||
	Host        string
 | 
			
		||||
	Port        int
 | 
			
		||||
	SslPolicyId     int64
 | 
			
		||||
	ListensJSON     []byte
 | 
			
		||||
	CertIdsJSON     []byte
 | 
			
		||||
	AccessAddrsJSON []byte
 | 
			
		||||
	Description     string
 | 
			
		||||
	IsOn            bool
 | 
			
		||||
 | 
			
		||||
	Must *actions.Must
 | 
			
		||||
}) {
 | 
			
		||||
	params.Must.
 | 
			
		||||
		Field("name", params.Name).
 | 
			
		||||
		Require("请输入API节点").
 | 
			
		||||
		Field("host", params.Host).
 | 
			
		||||
		Require("请输入主机地址").
 | 
			
		||||
		Field("port", params.Port).
 | 
			
		||||
		Gt(0, "端口不能小于1").
 | 
			
		||||
		Lte(65535, "端口不能大于65535")
 | 
			
		||||
		Require("请输入API节点名称")
 | 
			
		||||
 | 
			
		||||
	_, err := this.RPC().APINodeRPC().UpdateAPINode(this.AdminContext(), &pb.UpdateAPINodeRequest{
 | 
			
		||||
	httpConfig := &serverconfigs.HTTPProtocolConfig{}
 | 
			
		||||
	httpsConfig := &serverconfigs.HTTPSProtocolConfig{}
 | 
			
		||||
 | 
			
		||||
	// 监听地址
 | 
			
		||||
	listens := []*serverconfigs.NetworkAddressConfig{}
 | 
			
		||||
	err := json.Unmarshal(params.ListensJSON, &listens)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if len(listens) == 0 {
 | 
			
		||||
		this.Fail("请添加至少一个进程监听地址")
 | 
			
		||||
	}
 | 
			
		||||
	for _, addr := range listens {
 | 
			
		||||
		if addr.Protocol.IsHTTPFamily() {
 | 
			
		||||
			httpConfig.IsOn = true
 | 
			
		||||
			httpConfig.Listen = append(httpConfig.Listen, addr)
 | 
			
		||||
		} else if addr.Protocol.IsHTTPSFamily() {
 | 
			
		||||
			httpsConfig.IsOn = true
 | 
			
		||||
			httpsConfig.Listen = append(httpsConfig.Listen, addr)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 证书
 | 
			
		||||
	certIds := []int64{}
 | 
			
		||||
	if len(params.CertIdsJSON) > 0 {
 | 
			
		||||
		err = json.Unmarshal(params.CertIdsJSON, &certIds)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			this.ErrorPage(err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if httpsConfig.IsOn && len(httpsConfig.Listen) > 0 && len(certIds) == 0 {
 | 
			
		||||
		this.Fail("请添加至少一个证书")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	certRefs := []*sslconfigs.SSLCertRef{}
 | 
			
		||||
	for _, certId := range certIds {
 | 
			
		||||
		certRefs = append(certRefs, &sslconfigs.SSLCertRef{
 | 
			
		||||
			IsOn:   true,
 | 
			
		||||
			CertId: certId,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	certRefsJSON, err := json.Marshal(certRefs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 创建策略
 | 
			
		||||
	sslPolicyId := params.SslPolicyId
 | 
			
		||||
	if sslPolicyId == 0 {
 | 
			
		||||
		if len(certIds) > 0 {
 | 
			
		||||
			sslPolicyCreateResp, err := this.RPC().SSLPolicyRPC().CreateSSLPolicy(this.AdminContext(), &pb.CreateSSLPolicyRequest{
 | 
			
		||||
				CertsJSON: certRefsJSON,
 | 
			
		||||
			})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				this.ErrorPage(err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			sslPolicyId = sslPolicyCreateResp.SslPolicyId
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		_, err = this.RPC().SSLPolicyRPC().UpdateSSLPolicy(this.AdminContext(), &pb.UpdateSSLPolicyRequest{
 | 
			
		||||
			SslPolicyId: sslPolicyId,
 | 
			
		||||
			CertsJSON:   certRefsJSON,
 | 
			
		||||
		})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			this.ErrorPage(err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	httpsConfig.SSLPolicyRef = &sslconfigs.SSLPolicyRef{
 | 
			
		||||
		IsOn:        true,
 | 
			
		||||
		SSLPolicyId: sslPolicyId,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 访问地址
 | 
			
		||||
	accessAddrs := []*serverconfigs.NetworkAddressConfig{}
 | 
			
		||||
	err = json.Unmarshal(params.AccessAddrsJSON, &accessAddrs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if len(accessAddrs) == 0 {
 | 
			
		||||
		this.Fail("请添加至少一个外部访问地址")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	httpJSON, err := json.Marshal(httpConfig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	httpsJSON, err := json.Marshal(httpsConfig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = this.RPC().APINodeRPC().UpdateAPINode(this.AdminContext(), &pb.UpdateAPINodeRequest{
 | 
			
		||||
		NodeId:          params.NodeId,
 | 
			
		||||
		Name:            params.Name,
 | 
			
		||||
		Description:     params.Description,
 | 
			
		||||
		Host:        params.Host,
 | 
			
		||||
		Port:        int32(params.Port),
 | 
			
		||||
		HttpJSON:        httpJSON,
 | 
			
		||||
		HttpsJSON:       httpsJSON,
 | 
			
		||||
		AccessAddrsJSON: params.AccessAddrsJSON,
 | 
			
		||||
		IsOn:            params.IsOn,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										42
									
								
								internal/web/actions/default/api/node/updateAddrPopup.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								internal/web/actions/default/api/node/updateAddrPopup.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
package node
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
	"net"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type UpdateAddrPopupAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *UpdateAddrPopupAction) Init() {
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *UpdateAddrPopupAction) RunGet(params struct{}) {
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *UpdateAddrPopupAction) RunPost(params struct {
 | 
			
		||||
	Protocol string
 | 
			
		||||
	Addr     string
 | 
			
		||||
	Must     *actions.Must
 | 
			
		||||
}) {
 | 
			
		||||
	params.Must.
 | 
			
		||||
		Field("addr", params.Addr).
 | 
			
		||||
		Require("请输入访问地址")
 | 
			
		||||
	host, port, err := net.SplitHostPort(params.Addr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.FailField("addr", "错误的访问地址")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	addrConfig := &serverconfigs.NetworkAddressConfig{
 | 
			
		||||
		Protocol:  serverconfigs.Protocol(params.Protocol),
 | 
			
		||||
		Host:      host,
 | 
			
		||||
		PortRange: port,
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["addr"] = addrConfig
 | 
			
		||||
	this.Success()
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
package node
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
	"strings"
 | 
			
		||||
@@ -76,7 +76,7 @@ func (this *InstallAction) RunGet(params struct {
 | 
			
		||||
	apiNodes := apiNodesResp.Nodes
 | 
			
		||||
	apiEndpoints := []string{}
 | 
			
		||||
	for _, apiNode := range apiNodes {
 | 
			
		||||
		apiEndpoints = append(apiEndpoints, apiNode.Address)
 | 
			
		||||
		apiEndpoints = append(apiEndpoints, apiNode.AccessAddrs...)
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										155
									
								
								internal/web/actions/default/nodes/nodeutils/utils.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								internal/web/actions/default/nodes/nodeutils/utils.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
			
		||||
package nodeutils
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/configs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type MessageResult struct {
 | 
			
		||||
	NodeId   int64  `json:"nodeId"`
 | 
			
		||||
	NodeName string `json:"nodeName"`
 | 
			
		||||
	IsOK     bool   `json:"isOk"`
 | 
			
		||||
	Message  string `json:"message"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 向集群发送命令消息
 | 
			
		||||
func SendMessageToCluster(ctx context.Context, clusterId int64, code string, msg interface{}, timeoutSeconds int32) (results []*MessageResult, err error) {
 | 
			
		||||
	results = []*MessageResult{}
 | 
			
		||||
 | 
			
		||||
	msgJSON, err := json.Marshal(msg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return results, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defaultRPCClient, err := rpc.SharedRPC()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return results, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 获取所有节点
 | 
			
		||||
	nodesResp, err := defaultRPCClient.NodeRPC().FindAllEnabledNodesWithClusterId(ctx, &pb.FindAllEnabledNodesWithClusterIdRequest{ClusterId: clusterId})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return results, err
 | 
			
		||||
	}
 | 
			
		||||
	nodes := nodesResp.Nodes
 | 
			
		||||
	if len(nodes) == 0 {
 | 
			
		||||
		return results, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rpcMap := map[int64]*rpc.RPCClient{} // apiNodeId => RPCClient
 | 
			
		||||
	locker := &sync.Mutex{}
 | 
			
		||||
 | 
			
		||||
	wg := &sync.WaitGroup{}
 | 
			
		||||
	wg.Add(len(nodes))
 | 
			
		||||
	for _, node := range nodes {
 | 
			
		||||
		if len(node.ConnectedAPINodeIds) == 0 {
 | 
			
		||||
			locker.Lock()
 | 
			
		||||
			results = append(results, &MessageResult{
 | 
			
		||||
				NodeId:   node.Id,
 | 
			
		||||
				NodeName: node.Name,
 | 
			
		||||
				IsOK:     false,
 | 
			
		||||
				Message:  "节点尚未连接到API",
 | 
			
		||||
			})
 | 
			
		||||
			locker.Unlock()
 | 
			
		||||
			wg.Done()
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 获取API节点信息
 | 
			
		||||
		apiNodeId := node.ConnectedAPINodeIds[0]
 | 
			
		||||
		rpcClient, ok := rpcMap[apiNodeId]
 | 
			
		||||
		if !ok {
 | 
			
		||||
			apiNodeResp, err := defaultRPCClient.APINodeRPC().FindEnabledAPINode(ctx, &pb.FindEnabledAPINodeRequest{NodeId: apiNodeId})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				locker.Lock()
 | 
			
		||||
				results = append(results, &MessageResult{
 | 
			
		||||
					NodeId:   node.Id,
 | 
			
		||||
					NodeName: node.Name,
 | 
			
		||||
					IsOK:     false,
 | 
			
		||||
					Message:  "无法读取对应的API节点信息:" + err.Error(),
 | 
			
		||||
				})
 | 
			
		||||
				locker.Unlock()
 | 
			
		||||
				wg.Done()
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if apiNodeResp.Node == nil {
 | 
			
		||||
				locker.Lock()
 | 
			
		||||
				results = append(results, &MessageResult{
 | 
			
		||||
					NodeId:   node.Id,
 | 
			
		||||
					NodeName: node.Name,
 | 
			
		||||
					IsOK:     false,
 | 
			
		||||
					Message:  "无法读取对应的API节点信息:API节点ID:" + strconv.FormatInt(apiNodeId, 10),
 | 
			
		||||
				})
 | 
			
		||||
				locker.Unlock()
 | 
			
		||||
				wg.Done()
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			apiNode := apiNodeResp.Node
 | 
			
		||||
 | 
			
		||||
			apiRPCClient, err := rpc.NewRPCClient(&configs.APIConfig{
 | 
			
		||||
				RPC: struct {
 | 
			
		||||
					Endpoints []string `yaml:"endpoints"`
 | 
			
		||||
				}{
 | 
			
		||||
					Endpoints: apiNode.AccessAddrs,
 | 
			
		||||
				},
 | 
			
		||||
				NodeId: apiNode.UniqueId,
 | 
			
		||||
				Secret: apiNode.Secret,
 | 
			
		||||
			})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				locker.Lock()
 | 
			
		||||
				results = append(results, &MessageResult{
 | 
			
		||||
					NodeId:   node.Id,
 | 
			
		||||
					NodeName: node.Name,
 | 
			
		||||
					IsOK:     false,
 | 
			
		||||
					Message:  "初始化API节点错误:API节点ID:" + strconv.FormatInt(apiNodeId, 10) + ":" + err.Error(),
 | 
			
		||||
				})
 | 
			
		||||
				locker.Unlock()
 | 
			
		||||
				wg.Done()
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			rpcMap[apiNodeId] = apiRPCClient
 | 
			
		||||
			rpcClient = apiRPCClient
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 发送消息
 | 
			
		||||
		go func(node *pb.Node) {
 | 
			
		||||
			defer wg.Done()
 | 
			
		||||
 | 
			
		||||
			result, err := rpcClient.NodeRPC().SendCommandToNode(ctx, &pb.NodeStreamMessage{
 | 
			
		||||
				NodeId:         node.Id,
 | 
			
		||||
				TimeoutSeconds: timeoutSeconds,
 | 
			
		||||
				Code:           code,
 | 
			
		||||
				DataJSON:       msgJSON,
 | 
			
		||||
			})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				locker.Lock()
 | 
			
		||||
				results = append(results, &MessageResult{
 | 
			
		||||
					NodeId:   node.Id,
 | 
			
		||||
					NodeName: node.Name,
 | 
			
		||||
					IsOK:     false,
 | 
			
		||||
					Message:  "API返回错误:" + err.Error(),
 | 
			
		||||
				})
 | 
			
		||||
				locker.Unlock()
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			locker.Lock()
 | 
			
		||||
			results = append(results, &MessageResult{
 | 
			
		||||
				NodeId:   node.Id,
 | 
			
		||||
				NodeName: node.Name,
 | 
			
		||||
				IsOK:     result.IsOk,
 | 
			
		||||
				Message:  result.Message,
 | 
			
		||||
			})
 | 
			
		||||
			locker.Unlock()
 | 
			
		||||
		}(node)
 | 
			
		||||
	}
 | 
			
		||||
	wg.Wait()
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								internal/web/actions/default/nodes/nodeutils/utils_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								internal/web/actions/default/nodes/nodeutils/utils_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
package nodeutils
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
 | 
			
		||||
	_ "github.com/iwind/TeaGo/bootstrap"
 | 
			
		||||
	"github.com/iwind/TeaGo/logs"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestSendMessageToCluster(t *testing.T) {
 | 
			
		||||
	rpcClient, err := rpc.SharedRPC()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	ctx := rpcClient.Context(1)
 | 
			
		||||
 | 
			
		||||
	results, err := SendMessageToCluster(ctx, 1, "test", nil, 30)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	logs.PrintAsJSON(results, t)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								internal/web/actions/default/servers/components/cache/cacheutils/utils.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								internal/web/actions/default/servers/components/cache/cacheutils/utils.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
package cacheutils
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/errors"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 查找缓存策略名称并忽略错误
 | 
			
		||||
func FindCachePolicyNameWithoutError(parent *actionutils.ParentAction, cachePolicyId int64) string {
 | 
			
		||||
	policy, err := FindCachePolicy(parent, cachePolicyId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	if policy == nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	return policy.Name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 查找缓存策略配置
 | 
			
		||||
func FindCachePolicy(parent *actionutils.ParentAction, cachePolicyId int64) (*serverconfigs.HTTPCachePolicy, error) {
 | 
			
		||||
	resp, err := parent.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(parent.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{CachePolicyId: cachePolicyId})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if len(resp.CachePolicyJSON) == 0 {
 | 
			
		||||
		return nil, errors.New("cache policy not found")
 | 
			
		||||
	}
 | 
			
		||||
	config := &serverconfigs.HTTPCachePolicy{}
 | 
			
		||||
	err = json.Unmarshal(resp.CachePolicyJSON, config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return config, nil
 | 
			
		||||
}
 | 
			
		||||
@@ -7,7 +7,7 @@ type CleanAction struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *CleanAction) Init() {
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
	this.Nav("", "", "clean")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *CleanAction) RunGet(params struct{}) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,11 @@
 | 
			
		||||
package cache
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache/cacheutils"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"reflect"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Helper struct {
 | 
			
		||||
@@ -12,11 +15,23 @@ func NewHelper() *Helper {
 | 
			
		||||
	return &Helper{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *Helper) BeforeAction(action *actions.ActionObject) {
 | 
			
		||||
func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) {
 | 
			
		||||
	action := actionPtr.Object()
 | 
			
		||||
	if action.Request.Method != http.MethodGet {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	action.Data["mainTab"] = "component"
 | 
			
		||||
	action.Data["secondMenuItem"] = "cache"
 | 
			
		||||
 | 
			
		||||
	cachePolicyId := action.ParamInt64("cachePolicyId")
 | 
			
		||||
	action.Data["cachePolicyId"] = cachePolicyId
 | 
			
		||||
 | 
			
		||||
	parentActionValue := reflect.ValueOf(actionPtr).Elem().FieldByName("ParentAction")
 | 
			
		||||
	if parentActionValue.IsValid() {
 | 
			
		||||
		parentAction, isOk := parentActionValue.Interface().(actionutils.ParentAction)
 | 
			
		||||
		if isOk {
 | 
			
		||||
			action.Data["cachePolicyName"] = cacheutils.FindCachePolicyNameWithoutError(&parentAction, cachePolicyId)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,13 +16,15 @@ func init() {
 | 
			
		||||
			Get("", new(IndexAction)).
 | 
			
		||||
			GetPost("/createPopup", new(CreatePopupAction)).
 | 
			
		||||
			Get("/policy", new(PolicyAction)).
 | 
			
		||||
			GetPost("/updatePopup", new(UpdatePopupAction)).
 | 
			
		||||
			GetPost("/update", new(UpdateAction)).
 | 
			
		||||
			GetPost("/clean", new(CleanAction)).
 | 
			
		||||
			GetPost("/preheat", new(PreheatAction)).
 | 
			
		||||
			GetPost("/purge", new(PurgeAction)).
 | 
			
		||||
			GetPost("/stat", new(StatAction)).
 | 
			
		||||
			GetPost("/test", new(TestAction)).
 | 
			
		||||
			Post("/delete", new(DeleteAction)).
 | 
			
		||||
			Post("/testRead", new(TestReadAction)).
 | 
			
		||||
			Post("/testWrite", new(TestWriteAction)).
 | 
			
		||||
			EndAll()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,30 @@
 | 
			
		||||
package cache
 | 
			
		||||
 | 
			
		||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache/cacheutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type PolicyAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *PolicyAction) Init() {
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
	this.Nav("", "", "index")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *PolicyAction) RunGet(params struct{}) {
 | 
			
		||||
func (this *PolicyAction) RunGet(params struct {
 | 
			
		||||
	CachePolicyId int64
 | 
			
		||||
}) {
 | 
			
		||||
	cachePolicy, err := cacheutils.FindCachePolicy(this.Parent(), params.CachePolicyId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["cachePolicy"] = cachePolicy
 | 
			
		||||
 | 
			
		||||
	this.Data["typeName"] = serverconfigs.FindCachePolicyTypeName(cachePolicy.Type)
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ type PreheatAction struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *PreheatAction) Init() {
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
	this.Nav("", "", "preheat")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *PreheatAction) RunGet(params struct{}) {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ type PurgeAction struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *PurgeAction) Init() {
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
	this.Nav("", "", "purge")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *PurgeAction) RunGet(params struct{}) {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ type StatAction struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *StatAction) Init() {
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
	this.Nav("", "", "stat")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *StatAction) RunGet(params struct{}) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,34 @@
 | 
			
		||||
package cache
 | 
			
		||||
 | 
			
		||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type TestAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *TestAction) Init() {
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
	this.Nav("", "", "test")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *TestAction) RunGet(params struct{}) {
 | 
			
		||||
	// 集群列表
 | 
			
		||||
	clustersResp, err := this.RPC().NodeClusterRPC().FindAllEnabledNodeClusters(this.AdminContext(), &pb.FindAllEnabledNodeClustersRequest{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	clusterMaps := []maps.Map{}
 | 
			
		||||
	for _, cluster := range clustersResp.Clusters {
 | 
			
		||||
		clusterMaps = append(clusterMaps, maps.Map{
 | 
			
		||||
			"id":   cluster.Id,
 | 
			
		||||
			"name": cluster.Name,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["clusters"] = clusterMaps
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										52
									
								
								internal/web/actions/default/servers/components/cache/testRead.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								internal/web/actions/default/servers/components/cache/testRead.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
package cache
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/nodeutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type TestReadAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *TestReadAction) RunPost(params struct {
 | 
			
		||||
	ClusterId     int64
 | 
			
		||||
	CachePolicyId int64
 | 
			
		||||
	Key           string
 | 
			
		||||
}) {
 | 
			
		||||
	cachePolicyResp, err := this.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{CachePolicyId: params.CachePolicyId})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	cachePolicyJSON := cachePolicyResp.CachePolicyJSON
 | 
			
		||||
	if len(cachePolicyJSON) == 0 {
 | 
			
		||||
		this.Fail("找不到要操作的缓存策略")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 发送命令
 | 
			
		||||
	msg := &messageconfigs.ReadCacheMessage{
 | 
			
		||||
		CachePolicyJSON: cachePolicyJSON,
 | 
			
		||||
		Key:             params.Key,
 | 
			
		||||
	}
 | 
			
		||||
	results, err := nodeutils.SendMessageToCluster(this.AdminContext(), params.ClusterId, messageconfigs.MessageCodeReadCache, msg, 10)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	isAllOk := true
 | 
			
		||||
	for _, result := range results {
 | 
			
		||||
		if !result.IsOK {
 | 
			
		||||
			isAllOk = false
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Data["isAllOk"] = isAllOk
 | 
			
		||||
	this.Data["results"] = results
 | 
			
		||||
 | 
			
		||||
	this.Success()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										55
									
								
								internal/web/actions/default/servers/components/cache/testWrite.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								internal/web/actions/default/servers/components/cache/testWrite.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
package cache
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/nodeutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type TestWriteAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *TestWriteAction) RunPost(params struct {
 | 
			
		||||
	ClusterId     int64
 | 
			
		||||
	CachePolicyId int64
 | 
			
		||||
	Key           string
 | 
			
		||||
	Value         string
 | 
			
		||||
}) {
 | 
			
		||||
	cachePolicyResp, err := this.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{CachePolicyId: params.CachePolicyId})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	cachePolicyJSON := cachePolicyResp.CachePolicyJSON
 | 
			
		||||
	if len(cachePolicyJSON) == 0 {
 | 
			
		||||
		this.Fail("找不到要操作的缓存策略")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 发送命令
 | 
			
		||||
	msg := &messageconfigs.WriteCacheMessage{
 | 
			
		||||
		CachePolicyJSON: cachePolicyJSON,
 | 
			
		||||
		Key:             params.Key,
 | 
			
		||||
		Value:           []byte(params.Value),
 | 
			
		||||
		LifeSeconds:     3600,
 | 
			
		||||
	}
 | 
			
		||||
	results, err := nodeutils.SendMessageToCluster(this.AdminContext(), params.ClusterId, messageconfigs.MessageCodeWriteCache, msg, 10)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	isAllOk := true
 | 
			
		||||
	for _, result := range results {
 | 
			
		||||
		if !result.IsOK {
 | 
			
		||||
			isAllOk = false
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Data["isAllOk"] = isAllOk
 | 
			
		||||
	this.Data["results"] = results
 | 
			
		||||
 | 
			
		||||
	this.Success()
 | 
			
		||||
}
 | 
			
		||||
@@ -8,15 +8,15 @@ import (
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type UpdatePopupAction struct {
 | 
			
		||||
type UpdateAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *UpdatePopupAction) Init() {
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
func (this *UpdateAction) Init() {
 | 
			
		||||
	this.Nav("", "", "update")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *UpdatePopupAction) RunGet(params struct {
 | 
			
		||||
func (this *UpdateAction) RunGet(params struct {
 | 
			
		||||
	CachePolicyId int64
 | 
			
		||||
}) {
 | 
			
		||||
	configResp, err := this.RPC().HTTPCachePolicyRPC().FindEnabledHTTPCachePolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPCachePolicyConfigRequest{CachePolicyId: params.CachePolicyId})
 | 
			
		||||
@@ -44,7 +44,7 @@ func (this *UpdatePopupAction) RunGet(params struct {
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *UpdatePopupAction) RunPost(params struct {
 | 
			
		||||
func (this *UpdateAction) RunPost(params struct {
 | 
			
		||||
	CachePolicyId int64
 | 
			
		||||
 | 
			
		||||
	Name string
 | 
			
		||||
@@ -78,7 +78,7 @@ func (this *ServerHelper) createLeftMenu(action *actions.ActionObject) {
 | 
			
		||||
	// TABBAR
 | 
			
		||||
	selectedTabbar, _ := action.Data["mainTab"]
 | 
			
		||||
	tabbar := actionutils.NewTabbar()
 | 
			
		||||
	tabbar.Add("服务首页", "", "/servers", "", false)
 | 
			
		||||
	tabbar.Add("服务列表", "", "/servers", "", false)
 | 
			
		||||
	//tabbar.Add("看板", "", "/servers/server/board?serverId="+serverIdString, "dashboard", selectedTabbar == "board")
 | 
			
		||||
	tabbar.Add("日志", "", "/servers/server/log?serverId="+serverIdString, "history", selectedTabbar == "log")
 | 
			
		||||
	//tabbar.Add("统计", "", "/servers/server/stat?serverId="+serverIdString, "chart area", selectedTabbar == "stat")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										56
									
								
								web/public/js/components/api-node/api-node-addresses-box.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								web/public/js/components/api-node/api-node-addresses-box.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
Vue.component("api-node-addresses-box", {
 | 
			
		||||
	props: ["v-addrs", "v-name"],
 | 
			
		||||
	data: function () {
 | 
			
		||||
		let addrs = this.vAddrs
 | 
			
		||||
		if (addrs == null) {
 | 
			
		||||
			addrs = []
 | 
			
		||||
		}
 | 
			
		||||
		return {
 | 
			
		||||
			addrs: addrs
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 添加IP地址
 | 
			
		||||
		addAddr: function () {
 | 
			
		||||
			let that = this;
 | 
			
		||||
			teaweb.popup("/api/node/createAddrPopup", {
 | 
			
		||||
				height: "16em",
 | 
			
		||||
				callback: function (resp) {
 | 
			
		||||
					that.addrs.push(resp.data.addr);
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// 修改地址
 | 
			
		||||
		updateAddr: function (index, addr) {
 | 
			
		||||
			let that = this;
 | 
			
		||||
			window.UPDATING_ADDR = addr
 | 
			
		||||
			teaweb.popup("/api/node/updateAddrPopup?addressId=", {
 | 
			
		||||
				callback: function (resp) {
 | 
			
		||||
					Vue.set(that.addrs, index, resp.data.addr);
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// 删除IP地址
 | 
			
		||||
		removeAddr: function (index) {
 | 
			
		||||
			this.addrs.$remove(index);
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	template: `<div>
 | 
			
		||||
	<input type="hidden" :name="vName" :value="JSON.stringify(addrs)"/>
 | 
			
		||||
	<div v-if="addrs.length > 0">
 | 
			
		||||
		<div>
 | 
			
		||||
			<div v-for="(addr, index) in addrs" class="ui label small">
 | 
			
		||||
				{{addr.protocol}}://{{addr.host}}:{{addr.portRange}}</span>
 | 
			
		||||
				<a href="" title="修改" @click.prevent="updateAddr(index, addr)"><i class="icon pencil small"></i></a>
 | 
			
		||||
				<a href="" title="删除" @click.prevent="removeAddr(index)"><i class="icon remove"></i></a>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="ui divider"></div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div>
 | 
			
		||||
		<button class="ui button small" type="button" @click.prevent="addAddr()">+</button>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>`
 | 
			
		||||
})
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
Vue.component("network-addresses-box", {
 | 
			
		||||
	props: ["v-server-type", "v-addresses", "v-protocol"],
 | 
			
		||||
	props: ["v-server-type", "v-addresses", "v-protocol", "v-name"],
 | 
			
		||||
	data: function () {
 | 
			
		||||
		let addresses = this.vAddresses
 | 
			
		||||
		if (addresses == null) {
 | 
			
		||||
@@ -9,9 +9,16 @@ Vue.component("network-addresses-box", {
 | 
			
		||||
		if (protocol == null) {
 | 
			
		||||
			protocol = ""
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		let name = this.vName
 | 
			
		||||
		if (name == null) {
 | 
			
		||||
			name = "addresses"
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return {
 | 
			
		||||
			addresses: addresses,
 | 
			
		||||
			protocol: protocol
 | 
			
		||||
			protocol: protocol,
 | 
			
		||||
			name: name
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	watch: {
 | 
			
		||||
@@ -24,22 +31,28 @@ Vue.component("network-addresses-box", {
 | 
			
		||||
			let that = this
 | 
			
		||||
			teaweb.popup("/servers/addPortPopup?serverType=" + this.vServerType + "&protocol=" + this.protocol, {
 | 
			
		||||
				callback: function (resp) {
 | 
			
		||||
					var addr = resp.data.address;
 | 
			
		||||
					that.addresses.push(addr);
 | 
			
		||||
					var addr = resp.data.address
 | 
			
		||||
					that.addresses.push(addr)
 | 
			
		||||
					if (["https", "https4", "https6"].$contains(addr.protocol)) {
 | 
			
		||||
						this.tlsProtocolName = "HTTPS";
 | 
			
		||||
						this.tlsProtocolName = "HTTPS"
 | 
			
		||||
					} else if (["tls", "tls4", "tls6"].$contains(addr.protocol)) {
 | 
			
		||||
						this.tlsProtocolName = "TLS";
 | 
			
		||||
						this.tlsProtocolName = "TLS"
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// 发送事件
 | 
			
		||||
					that.$emit("change", that.addresses)
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
		},
 | 
			
		||||
		removeAddr: function (index) {
 | 
			
		||||
			this.addresses.$remove(index);
 | 
			
		||||
 | 
			
		||||
			// 发送事件
 | 
			
		||||
			this.$emit("change", this.addresses)
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	template: `<div>
 | 
			
		||||
	<input type="hidden" name="addresses" :value="JSON.stringify(addresses)"/>
 | 
			
		||||
	<input type="hidden" :name="name" :value="JSON.stringify(addresses)"/>
 | 
			
		||||
	<div v-if="addresses.length > 0">
 | 
			
		||||
		<div class="ui label small" v-for="(addr, index) in addresses">
 | 
			
		||||
			{{addr.protocol}}://<span v-if="addr.host.length > 0">{{addr.host}}</span><span v-if="addr.host.length == 0">*</span>:{{addr.portRange}}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								web/public/js/components/common/size-capacity-view.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								web/public/js/components/common/size-capacity-view.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
Vue.component("size-capacity-view", {
 | 
			
		||||
	props:["v-default-text", "v-value"],
 | 
			
		||||
	template: `<div>
 | 
			
		||||
	<span v-if="vValue != null && vValue.count > 0">{{vValue.count}}{{vValue.unit.toUpperCase()}}</span>
 | 
			
		||||
	<span v-else>{{vDefaultText}}</span>
 | 
			
		||||
</div>`
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										71
									
								
								web/public/js/components/server/ssl-certs-box.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								web/public/js/components/server/ssl-certs-box.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
Vue.component("ssl-certs-box", {
 | 
			
		||||
	props: ["v-certs", "v-protocol"],
 | 
			
		||||
	data: function () {
 | 
			
		||||
		let certs = this.vCerts
 | 
			
		||||
		if (certs == null) {
 | 
			
		||||
			certs = []
 | 
			
		||||
		}
 | 
			
		||||
		return {
 | 
			
		||||
			certs: certs
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		certIds: function () {
 | 
			
		||||
			return this.certs.map(function (v) {
 | 
			
		||||
				return v.id
 | 
			
		||||
			})
 | 
			
		||||
		},
 | 
			
		||||
		// 删除证书
 | 
			
		||||
		removeCert: function (index) {
 | 
			
		||||
			let that = this
 | 
			
		||||
			teaweb.confirm("确定删除此证书吗?证书数据仍然保留,只是当前服务不再使用此证书。", function () {
 | 
			
		||||
				that.certs.$remove(index)
 | 
			
		||||
			})
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// 选择证书
 | 
			
		||||
		selectCert: function () {
 | 
			
		||||
			let that = this
 | 
			
		||||
			teaweb.popup("/servers/components/ssl/selectPopup", {
 | 
			
		||||
				width: "50em",
 | 
			
		||||
				height: "30em",
 | 
			
		||||
				callback: function (resp) {
 | 
			
		||||
					that.certs.push(resp.data.cert)
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// 上传证书
 | 
			
		||||
		uploadCert: function () {
 | 
			
		||||
			let that = this
 | 
			
		||||
			teaweb.popup("/servers/components/ssl/uploadPopup", {
 | 
			
		||||
				height: "28em",
 | 
			
		||||
				callback: function (resp) {
 | 
			
		||||
					teaweb.success("上传成功", function () {
 | 
			
		||||
						that.certs.push(resp.data.cert)
 | 
			
		||||
					})
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// 格式化时间
 | 
			
		||||
		formatTime: function (timestamp) {
 | 
			
		||||
			return new Date(timestamp * 1000).format("Y-m-d")
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	template: `<div>
 | 
			
		||||
	<input type="hidden" name="certIdsJSON" :value="JSON.stringify(certIds())"/>
 | 
			
		||||
	<div v-if="certs != null && certs.length > 0">
 | 
			
		||||
		<div class="ui label small" v-for="(cert, index) in certs">
 | 
			
		||||
			{{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   <a href="" title="删除" @click.prevent="removeCert()"><i class="icon remove"></i></a>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="ui divider"></div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div v-else>
 | 
			
		||||
		<span class="red">选择或上传证书后<span v-if="vProtocol == 'https'">HTTPS</span><span v-if="vProtocol == 'tls'">TLS</span>服务才能生效。</span>
 | 
			
		||||
		<div class="ui divider"></div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<button class="ui button tiny" type="button" @click.prevent="selectCert()">选择已有证书</button>  
 | 
			
		||||
	<button class="ui button tiny" type="button" @click.prevent="uploadCert()">上传新证书</button>
 | 
			
		||||
</div>`
 | 
			
		||||
})
 | 
			
		||||
@@ -8,15 +8,21 @@
 | 
			
		||||
	<thead>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<th>节点名称</th>
 | 
			
		||||
			<th>主机地址</th>
 | 
			
		||||
			<th>端口</th>
 | 
			
		||||
			<th>访问地址</th>
 | 
			
		||||
			<th class="two wide">状态</th>
 | 
			
		||||
			<th class="two op">操作</th>
 | 
			
		||||
		</tr>
 | 
			
		||||
	</thead>
 | 
			
		||||
	<tr v-for="node in nodes">
 | 
			
		||||
		<td>{{node.name}}</td>
 | 
			
		||||
		<td>{{node.host}}</td>
 | 
			
		||||
		<td>{{node.port}}</td>
 | 
			
		||||
		<td>
 | 
			
		||||
			<div v-if="node.accessAddrs != null && node.accessAddrs.length > 0">
 | 
			
		||||
				<span class="ui label tiny" v-for="addr in node.accessAddrs">{{addr}}</span>
 | 
			
		||||
			</div>
 | 
			
		||||
		</td>
 | 
			
		||||
		<td>
 | 
			
		||||
			<label-on :v-is-on="node.isOn"></label-on>
 | 
			
		||||
		</td>
 | 
			
		||||
		<td>
 | 
			
		||||
			<a :href="'/api/node/settings?nodeId=' + node.id">设置</a>
 | 
			
		||||
		</td>
 | 
			
		||||
 
 | 
			
		||||
@@ -10,17 +10,23 @@
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td>主机地址 *</td>
 | 
			
		||||
			<td>进程监听端口 *</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<input type="text" name="host" maxlength="100"/>
 | 
			
		||||
				<p class="comment">IP地址或者域名。</p>
 | 
			
		||||
				<network-addresses-box :v-name="'listensJSON'" :v-server-type="'httpWeb'" @change="changeListens"></network-addresses-box>
 | 
			
		||||
				<p class="comment">API节点进程监听的网络端口。</p>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tr v-if="hasHTTPS">
 | 
			
		||||
			<td>HTTPS证书 *</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<ssl-certs-box :v-protocol="'https'"></ssl-certs-box>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td>端口 *</td>
 | 
			
		||||
			<td>外部访问地址 *</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<input type="text" name="port" maxlength="5" style="width:6em"/>
 | 
			
		||||
				<p class="comment">1-65535之间。</p>
 | 
			
		||||
				<api-node-addresses-box :v-name="'accessAddrsJSON'"></api-node-addresses-box>
 | 
			
		||||
				<p class="comment">外部访问API节点的网络地址。</p>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
 | 
			
		||||
@@ -34,6 +40,15 @@
 | 
			
		||||
					<textarea name="description" maxlength="200" rows="3"></textarea>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>是否启用</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<div class="ui checkbox">
 | 
			
		||||
						<input type="checkbox" name="isOn" value="1" checked="checked"/>
 | 
			
		||||
						<label></label>
 | 
			
		||||
					</div>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
		</tbody>
 | 
			
		||||
	</table>
 | 
			
		||||
	<submit-btn></submit-btn>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,10 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.success = NotifySuccess("保存成功", "/api")
 | 
			
		||||
 | 
			
		||||
	this.hasHTTPS = false
 | 
			
		||||
	this.changeListens = function (addrs) {
 | 
			
		||||
		this.hasHTTPS = addrs.$any(function (k, v) {
 | 
			
		||||
			return v.protocol == "https"
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										24
									
								
								web/views/@default/api/node/createAddrPopup.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								web/views/@default/api/node/createAddrPopup.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
{$layout "layout_popup"}
 | 
			
		||||
 | 
			
		||||
<h3>添加访问地址</h3>
 | 
			
		||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
 | 
			
		||||
	<table class="ui table definition selectable">
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td>网络协议</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<select class="ui dropdown auto-width" name="protocol">
 | 
			
		||||
					<option value="http">HTTP</option>
 | 
			
		||||
					<option value="https">HTTPS</option>
 | 
			
		||||
				</select>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td class="title">访问地址</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<input type="text" name="addr" maxlength="100" ref="focus"/>
 | 
			
		||||
				<p class="comment">可以是"IP:端口"或者"域名:端口"。</p>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
	</table>
 | 
			
		||||
	<submit-btn></submit-btn>
 | 
			
		||||
</form>
 | 
			
		||||
@@ -1,5 +1,3 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.success = NotifyPopup
 | 
			
		||||
 | 
			
		||||
	this.policyType = this.cachePolicy.type
 | 
			
		||||
})
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
<div class="right-box">
 | 
			
		||||
	<form class="ui form" data-tea-action="$" data-tea-success="success">
 | 
			
		||||
		<input type="hidden" name="nodeId" :value="node.id"/>
 | 
			
		||||
		<input type="hidden" name="sslPolicyId" :value="node.sslPolicyId"/>
 | 
			
		||||
		<table class="ui table selectable definition">
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td class="title">节点名称 *</td>
 | 
			
		||||
@@ -12,17 +13,23 @@
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>主机地址 *</td>
 | 
			
		||||
				<td>进程监听端口 *</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<input type="text" name="host" maxlength="100" v-model="node.host"/>
 | 
			
		||||
					<p class="comment">IP地址或者域名。</p>
 | 
			
		||||
					<network-addresses-box :v-name="'listensJSON'" :v-server-type="'httpWeb'" :v-addresses="node.listens" @change="changeListens"></network-addresses-box>
 | 
			
		||||
					<p class="comment">API节点进程监听的网络端口。</p>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			<tr v-if="hasHTTPS">
 | 
			
		||||
				<td>HTTPS证书 *</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<ssl-certs-box :v-certs="node.certs" :v-protocol="'https'"></ssl-certs-box>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>端口 *</td>
 | 
			
		||||
				<td>外部访问地址 *</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<input type="text" name="port" maxlength="5" style="width:6em" v-model="node.port"/>
 | 
			
		||||
					<p class="comment">1-65535之间。</p>
 | 
			
		||||
					<api-node-addresses-box :v-name="'accessAddrsJSON'" :v-addrs="node.accessAddrs"></api-node-addresses-box>
 | 
			
		||||
					<p class="comment">外部访问API节点的网络地址。</p>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
 | 
			
		||||
@@ -36,6 +43,15 @@
 | 
			
		||||
						<textarea name="description" maxlength="200" rows="3" v-model="node.description"></textarea>
 | 
			
		||||
					</td>
 | 
			
		||||
				</tr>
 | 
			
		||||
				<tr>
 | 
			
		||||
					<td>是否启用</td>
 | 
			
		||||
					<td>
 | 
			
		||||
						<div class="ui checkbox">
 | 
			
		||||
							<input type="checkbox" name="isOn" value="1" v-model="node.isOn"/>
 | 
			
		||||
							<label></label>
 | 
			
		||||
						</div>
 | 
			
		||||
					</td>
 | 
			
		||||
				</tr>
 | 
			
		||||
			</tbody>
 | 
			
		||||
		</table>
 | 
			
		||||
		<submit-btn></submit-btn>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,12 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.success = NotifySuccess("保存成功", "/api/node/settings?nodeId=" + this.node.id)
 | 
			
		||||
 | 
			
		||||
	this.hasHTTPS = this.node.listens.$any(function (k, v) {
 | 
			
		||||
		return v.protocol == "https"
 | 
			
		||||
	})
 | 
			
		||||
	this.changeListens = function (addrs) {
 | 
			
		||||
		this.hasHTTPS = addrs.$any(function (k, v) {
 | 
			
		||||
			return v.protocol == "https"
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										24
									
								
								web/views/@default/api/node/updateAddrPopup.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								web/views/@default/api/node/updateAddrPopup.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
{$layout "layout_popup"}
 | 
			
		||||
 | 
			
		||||
<h3>修改访问地址</h3>
 | 
			
		||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
 | 
			
		||||
	<table class="ui table definition selectable">
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td>网络协议</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<select class="ui dropdown auto-width" name="protocol" v-model="protocol">
 | 
			
		||||
					<option value="http">HTTP</option>
 | 
			
		||||
					<option value="https">HTTPS</option>
 | 
			
		||||
				</select>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td class="title">访问地址</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<input type="text" name="addr" maxlength="100" ref="focus" v-model="addr"/>
 | 
			
		||||
				<p class="comment">可以是"IP:端口"或者"域名:端口"。</p>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
	</table>
 | 
			
		||||
	<submit-btn></submit-btn>
 | 
			
		||||
</form>
 | 
			
		||||
							
								
								
									
										6
									
								
								web/views/@default/api/node/updateAddrPopup.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								web/views/@default/api/node/updateAddrPopup.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.success = NotifyPopup
 | 
			
		||||
	let addr = window.parent.UPDATING_ADDR
 | 
			
		||||
	this.protocol = addr.protocol
 | 
			
		||||
	this.addr = addr.host + ":" + addr.portRange
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										11
									
								
								web/views/@default/servers/components/cache/@policy_menu.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								web/views/@default/servers/components/cache/@policy_menu.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
<second-menu>
 | 
			
		||||
	<menu-item href="/servers/components/cache">列表</menu-item>
 | 
			
		||||
	<span class="item">|</span>
 | 
			
		||||
	<menu-item  :href="'/servers/components/cache/policy?cachePolicyId=' + cachePolicyId" code="index">{{cachePolicyName}}</menu-item>
 | 
			
		||||
	<menu-item :href="'/servers/components/cache/test?cachePolicyId=' + cachePolicyId" code="test">测试</menu-item>
 | 
			
		||||
	<menu-item  :href="'/servers/components/cache/stat?cachePolicyId=' + cachePolicyId" code="stat">统计</menu-item>
 | 
			
		||||
	<menu-item :href="'/servers/components/cache/clean?cachePolicyId=' + cachePolicyId" code="clean">清理</menu-item>
 | 
			
		||||
	<menu-item :href="'/servers/components/cache/purge?cachePolicyId=' + cachePolicyId" code="purge">删除</menu-item>
 | 
			
		||||
	<menu-item :href="'/servers/components/cache/preheat?cachePolicyId=' + cachePolicyId" code="preheat">预热</menu-item>
 | 
			
		||||
	<menu-item :href="'/servers/components/cache/update?cachePolicyId=' + cachePolicyId" code="update">修改</menu-item>
 | 
			
		||||
</second-menu>
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
			<td><input type="text" name="name" maxlength="100" ref="focus"/> </td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td>缓存类型 *</td>
 | 
			
		||||
			<td class="color-border">缓存类型 *</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<select class="ui dropdown auto-width" name="type" v-model="policyType">
 | 
			
		||||
					<option v-for="type in types" :value="type.type">{{type.name}}</option>
 | 
			
		||||
@@ -19,7 +19,7 @@
 | 
			
		||||
		<!-- 文件缓存选项 -->
 | 
			
		||||
		<tbody v-if="policyType == 'file'">
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>缓存目录 *</td>
 | 
			
		||||
				<td class="color-border">缓存目录 *</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<input type="text" name="fileDir" maxlength="500"/>
 | 
			
		||||
					<p class="comment">存放文件缓存的目录,通常填写绝对路径。</p>
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@
 | 
			
		||||
				<th>容量</th>
 | 
			
		||||
				<th>引用服务</th>
 | 
			
		||||
				<th>状态</th>
 | 
			
		||||
				<th class="three op">操作</th>
 | 
			
		||||
				<th class="two op">操作</th>
 | 
			
		||||
			</tr>
 | 
			
		||||
		</thead>
 | 
			
		||||
		<tr v-for="(policy, index) in cachePolicies">
 | 
			
		||||
@@ -30,7 +30,7 @@
 | 
			
		||||
			<td>{{infos[index].countServers}}</td>
 | 
			
		||||
			<td><label-on :v-is-on="policy.isOn"></label-on></td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<a :href="'/servers/components/cache/policy?cachePolicyId=' + policy.id">详情</a>   <a href="" @click.prevent="updatePolicy(policy.id)">修改</a>   <a href="" @click.prevent="deletePolicy(policy.id)">删除</a>
 | 
			
		||||
				<a :href="'/servers/components/cache/policy?cachePolicyId=' + policy.id">详情</a>   <a href="" @click.prevent="deletePolicy(policy.id)">删除</a>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
	</table>
 | 
			
		||||
 
 | 
			
		||||
@@ -11,18 +11,6 @@ Tea.context(function () {
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 修改策略
 | 
			
		||||
	this.updatePolicy = function (policyId) {
 | 
			
		||||
		teaweb.popup("/servers/components/cache/updatePopup?cachePolicyId=" + policyId, {
 | 
			
		||||
			height: "27em",
 | 
			
		||||
			callback: function () {
 | 
			
		||||
				teaweb.success("保存成功", function () {
 | 
			
		||||
					window.location.reload()
 | 
			
		||||
				})
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 删除策略
 | 
			
		||||
	this.deletePolicy = function (policyId) {
 | 
			
		||||
		let that = this
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										69
									
								
								web/views/@default/servers/components/cache/policy.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								web/views/@default/servers/components/cache/policy.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
{$layout}
 | 
			
		||||
{$template "/left_menu"}
 | 
			
		||||
 | 
			
		||||
<div class="right-box">
 | 
			
		||||
	{$template "policy_menu"}
 | 
			
		||||
 | 
			
		||||
	<table class="ui table definition selectable">
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td class="title">策略名称</td>
 | 
			
		||||
			<td>{{cachePolicy.name}}</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td>状态</td>
 | 
			
		||||
			<td><label-on :v-is-on="cachePolicy.isOn"></label-on></td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td class="color-border">缓存类型</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				{{typeName}}<span class="small">({{cachePolicy.type}})</span>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
 | 
			
		||||
		<!-- 文件缓存选项 -->
 | 
			
		||||
		<tbody v-if="cachePolicy.type == 'file'">
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td class="color-border">缓存目录</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				{{cachePolicy.options.dir}}
 | 
			
		||||
				<p class="comment">存放文件缓存的目录,通常填写绝对路径。</p>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		</tbody>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td>缓存最大容量</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<size-capacity-view :v-value="cachePolicy.capacity" :v-default-text="'不限'"></size-capacity-view>
 | 
			
		||||
				<p class="comment">允许缓存的最大内容长度,如果为0表示没有限制。</p>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td colspan="2"><more-options-indicator></more-options-indicator></td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tbody v-show="moreOptionsVisible">
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td>最大内容长度</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<size-capacity-view :v-value="cachePolicy.maxSize" :v-default-text="'不限'"></size-capacity-view>
 | 
			
		||||
				<p class="comment">允许缓存的最大内容长度,如果为0表示没有限制。</p>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td>容纳Key数量</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<span v-if="cachePolicy.maxKeys > 0">{{cachePolicy.maxKeys}}</span>
 | 
			
		||||
				<span v-else>不限</span>
 | 
			
		||||
				<p class="comment">可以容纳多少数量的Key,0表示不限制。</p>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td>描述</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				{{cachePolicy.description}}
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		</tbody>
 | 
			
		||||
	</table>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										73
									
								
								web/views/@default/servers/components/cache/test.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								web/views/@default/servers/components/cache/test.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
{$layout}
 | 
			
		||||
{$template "/left_menu"}
 | 
			
		||||
 | 
			
		||||
<div class="right-box">
 | 
			
		||||
	{$template "policy_menu"}
 | 
			
		||||
 | 
			
		||||
	<h3>选择集群</h3>
 | 
			
		||||
	<select class="ui dropdown auto-width" v-model="clusterId">
 | 
			
		||||
		<option v-for="cluster in clusters" :value="cluster.id">{{cluster.name}}</option>
 | 
			
		||||
	</select>
 | 
			
		||||
 | 
			
		||||
	<div class="ui divider"></div>
 | 
			
		||||
 | 
			
		||||
	<h3>测试写入</h3>
 | 
			
		||||
	<form class="ui form" data-tea-action=".testWrite" data-tea-before="beforeWrite" data-tea-done="doneWrite" data-tea-success="successWrite" data-tea-fail="failWrite">
 | 
			
		||||
		<input type="hidden" name="clusterId" :value="clusterId"/>
 | 
			
		||||
		<input type="hidden" name="cachePolicyId" :value="cachePolicyId"/>
 | 
			
		||||
		<table class="ui table selectable definition">
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td class="title">Key</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<input type="text" name="key" value="my-key"/>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>Value</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<textarea name="value" rows="3">my-value</textarea>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>操作结果</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<div v-if="isRequestingWrite">数据发送中...</div>
 | 
			
		||||
					<span class="red" v-if="!isRequestingWrite && !writeOk && writeMessage.length > 0">失败:{{writeMessage}}</span>
 | 
			
		||||
					<div v-if="!isRequestingWrite && writeOk">
 | 
			
		||||
						<span v-if="writeResults.length == 0" class="red">此集群下没有任何可用的节点。</span>
 | 
			
		||||
						<div class="ui label tiny" v-for="result in writeResults" :class="{green:result.isOk, red:!result.isOk}" style="margin-bottom:0.5em">节点{{result.nodeName}}:{{result.message}}</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
		</table>
 | 
			
		||||
		<submit-btn v-if="!isRequestingWrite">提交</submit-btn>
 | 
			
		||||
	</form>
 | 
			
		||||
 | 
			
		||||
	<div class="ui divider"></div>
 | 
			
		||||
 | 
			
		||||
	<h3>测试读取</h3>
 | 
			
		||||
	<form class="ui form" data-tea-action=".testRead" data-tea-before="beforeRead" data-tea-done="doneRead" data-tea-success="successRead" data-tea-fail="failRead">
 | 
			
		||||
		<input type="hidden" name="clusterId" :value="clusterId"/>
 | 
			
		||||
		<input type="hidden" name="cachePolicyId" :value="cachePolicyId"/>
 | 
			
		||||
		<table class="ui table selectable definition">
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td class="title">Key</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<input type="text" name="key" value="my-key"/>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>操作结果</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<div v-if="isRequestingRead">数据发送中...</div>
 | 
			
		||||
					<span class="red" v-if="!isRequestingRead && !readOk && readMessage.length > 0">失败:{{readMessage}}</span>
 | 
			
		||||
					<div v-if="!isRequestingRead && readOk">
 | 
			
		||||
						<span v-if="readResults.length == 0" class="red">此集群下没有任何可用的节点。</span>
 | 
			
		||||
						<div class="ui label tiny" v-for="result in readResults" :class="{green:result.isOk, red:!result.isOk}" style="margin-bottom: 0.5em">节点{{result.nodeName}}:{{result.message}}</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
		</table>
 | 
			
		||||
		<submit-btn v-if="!isRequestingRead">提交</submit-btn>
 | 
			
		||||
	</form>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										63
									
								
								web/views/@default/servers/components/cache/test.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								web/views/@default/servers/components/cache/test.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	if (this.clusters.length > 0) {
 | 
			
		||||
		this.clusterId = this.clusters[0].id
 | 
			
		||||
	} else {
 | 
			
		||||
		this.clusterId = 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.isRequestingWrite = false
 | 
			
		||||
	this.writeOk = false
 | 
			
		||||
	this.writeMessage = ""
 | 
			
		||||
	this.writeIsAllOk = false
 | 
			
		||||
	this.writeResults = []
 | 
			
		||||
 | 
			
		||||
	this.beforeWrite = function () {
 | 
			
		||||
		this.isRequestingWrite = true
 | 
			
		||||
		this.writeOk = false
 | 
			
		||||
		this.writeMessage = ""
 | 
			
		||||
		this.writeResult = {}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.failWrite = function (resp) {
 | 
			
		||||
		this.writeOk = false
 | 
			
		||||
		this.writeMessage = resp.message
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.successWrite = function (resp) {
 | 
			
		||||
		this.writeOk = true
 | 
			
		||||
		this.writeIsAllOk = resp.data.isAllOk
 | 
			
		||||
		this.writeResults = resp.data.results
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.doneWrite = function () {
 | 
			
		||||
		this.isRequestingWrite = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.isRequestingRead = false
 | 
			
		||||
	this.readOk = false
 | 
			
		||||
	this.readMessage = ""
 | 
			
		||||
	this.readIsAllOk = false
 | 
			
		||||
	this.readResults = []
 | 
			
		||||
 | 
			
		||||
	this.beforeRead = function () {
 | 
			
		||||
		this.isRequestingRead = true
 | 
			
		||||
		this.readOk = false
 | 
			
		||||
		this.readMessage = ""
 | 
			
		||||
		this.readResult = {}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.failRead = function (resp) {
 | 
			
		||||
		this.readOk = false
 | 
			
		||||
		this.readMessage = resp.message
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	this.successRead = function (resp) {
 | 
			
		||||
		this.readOk = true;
 | 
			
		||||
		this.readIsAllOk = resp.data.isAllOk
 | 
			
		||||
		this.readResults = resp.data.results
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.doneRead = function () {
 | 
			
		||||
		this.isRequestingRead = false
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										79
									
								
								web/views/@default/servers/components/cache/update.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								web/views/@default/servers/components/cache/update.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
{$layout}
 | 
			
		||||
{$template "/left_menu"}
 | 
			
		||||
 | 
			
		||||
<div class="right-box">
 | 
			
		||||
	{$template "policy_menu"}
 | 
			
		||||
 | 
			
		||||
	<form class="ui form" data-tea-action="$" data-tea-success="success">
 | 
			
		||||
		<input type="hidden" name="cachePolicyId" :value="cachePolicy.id"/>
 | 
			
		||||
		<table class="ui table definition selectable">
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td class="title">策略名称 *</td>
 | 
			
		||||
				<td><input type="text" name="name" maxlength="100" ref="focus" v-model="cachePolicy.name"/> </td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td class="color-border">缓存类型 *</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<select class="ui dropdown auto-width" name="type" v-model="policyType">
 | 
			
		||||
						<option v-for="type in types" :value="type.type">{{type.name}}</option>
 | 
			
		||||
					</select>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
 | 
			
		||||
			<!-- 文件缓存选项 -->
 | 
			
		||||
			<tbody v-if="policyType == 'file'">
 | 
			
		||||
				<tr>
 | 
			
		||||
					<td class="color-border">缓存目录 *</td>
 | 
			
		||||
					<td>
 | 
			
		||||
						<input type="text" name="fileDir" maxlength="500" v-model="cachePolicy.options.dir"/>
 | 
			
		||||
						<p class="comment">存放文件缓存的目录,通常填写绝对路径。</p>
 | 
			
		||||
					</td>
 | 
			
		||||
				</tr>
 | 
			
		||||
			</tbody>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>缓存最大容量</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<size-capacity-box :v-name="'capacityJSON'" :v-value="cachePolicy.capacity" :v-count="0" :v-unit="'gb'"></size-capacity-box>
 | 
			
		||||
					<p class="comment">允许缓存的最大内容长度,如果为0表示没有限制。</p>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td colspan="2"><more-options-indicator></more-options-indicator></td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			<tbody v-show="moreOptionsVisible">
 | 
			
		||||
				<tr>
 | 
			
		||||
					<td>最大内容长度</td>
 | 
			
		||||
					<td>
 | 
			
		||||
						<size-capacity-box :v-value="cachePolicy.maxSize" :v-name="'maxSizeJSON'" :v-count="32" :v-unit="'mb'"></size-capacity-box>
 | 
			
		||||
						<p class="comment">允许缓存的最大内容长度,如果为0表示没有限制。</p>
 | 
			
		||||
					</td>
 | 
			
		||||
				</tr>
 | 
			
		||||
				<tr>
 | 
			
		||||
					<td>容纳Key数量</td>
 | 
			
		||||
					<td>
 | 
			
		||||
						<input type="text" name="maxKeys" maxlength="10" style="width:10em" v-model="cachePolicy.maxKeys"/>
 | 
			
		||||
						<p class="comment">可以容纳多少数量的Key,0表示不限制。</p>
 | 
			
		||||
					</td>
 | 
			
		||||
				</tr>
 | 
			
		||||
				<tr>
 | 
			
		||||
					<td>描述</td>
 | 
			
		||||
					<td>
 | 
			
		||||
						<textarea maxlength="200" name="description" rows="3" v-model="cachePolicy.description"></textarea>
 | 
			
		||||
					</td>
 | 
			
		||||
				</tr>
 | 
			
		||||
				<tr>
 | 
			
		||||
					<td>是否启用</td>
 | 
			
		||||
					<td>
 | 
			
		||||
						<div class="ui checkbox">
 | 
			
		||||
							<input type="checkbox" name="isOn" value="1" v-model="cachePolicy.isOn"/>
 | 
			
		||||
							<label></label>
 | 
			
		||||
						</div>
 | 
			
		||||
					</td>
 | 
			
		||||
				</tr>
 | 
			
		||||
			</tbody>
 | 
			
		||||
		</table>
 | 
			
		||||
		<submit-btn></submit-btn>
 | 
			
		||||
	</form>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										5
									
								
								web/views/@default/servers/components/cache/update.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								web/views/@default/servers/components/cache/update.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.success = NotifyReloadSuccess("保存成功 ")
 | 
			
		||||
 | 
			
		||||
	this.policyType = this.cachePolicy.type
 | 
			
		||||
})
 | 
			
		||||
@@ -1,76 +0,0 @@
 | 
			
		||||
{$layout "layout_popup"}
 | 
			
		||||
 | 
			
		||||
<h3>修改缓存策略</h3>
 | 
			
		||||
 | 
			
		||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
 | 
			
		||||
	<input type="hidden" name="cachePolicyId" :value="cachePolicy.id"/>
 | 
			
		||||
	<table class="ui table definition selectable">
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td class="title">策略名称 *</td>
 | 
			
		||||
			<td><input type="text" name="name" maxlength="100" ref="focus" v-model="cachePolicy.name"/> </td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td>缓存类型 *</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<select class="ui dropdown auto-width" name="type" v-model="policyType">
 | 
			
		||||
					<option v-for="type in types" :value="type.type">{{type.name}}</option>
 | 
			
		||||
				</select>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
 | 
			
		||||
		<!-- 文件缓存选项 -->
 | 
			
		||||
		<tbody v-if="policyType == 'file'">
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>缓存目录 *</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<input type="text" name="fileDir" maxlength="500" v-model="cachePolicy.options.dir"/>
 | 
			
		||||
					<p class="comment">存放文件缓存的目录,通常填写绝对路径。</p>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
		</tbody>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td>缓存最大容量</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<size-capacity-box :v-name="'capacityJSON'" :v-value="cachePolicy.capacity" :v-count="0" :v-unit="'gb'"></size-capacity-box>
 | 
			
		||||
				<p class="comment">允许缓存的最大内容长度,如果为0表示没有限制。</p>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td colspan="2"><more-options-indicator></more-options-indicator></td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tbody v-show="moreOptionsVisible">
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>最大内容长度</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<size-capacity-box :v-value="cachePolicy.maxSize" :v-name="'maxSizeJSON'" :v-count="32" :v-unit="'mb'"></size-capacity-box>
 | 
			
		||||
					<p class="comment">允许缓存的最大内容长度,如果为0表示没有限制。</p>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>容纳Key数量</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<input type="text" name="maxKeys" maxlength="10" style="width:10em" v-model="cachePolicy.maxKeys"/>
 | 
			
		||||
					<p class="comment">可以容纳多少数量的Key,0表示不限制。</p>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>描述</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<textarea maxlength="200" name="description" rows="3" v-model="cachePolicy.description"></textarea>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>是否启用</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<div class="ui checkbox">
 | 
			
		||||
						<input type="checkbox" name="isOn" value="1" v-model="cachePolicy.isOn"/>
 | 
			
		||||
						<label></label>
 | 
			
		||||
					</div>
 | 
			
		||||
				</td>
 | 
			
		||||
			</tr>
 | 
			
		||||
		</tbody>
 | 
			
		||||
	</table>
 | 
			
		||||
	<submit-btn></submit-btn>
 | 
			
		||||
</form>
 | 
			
		||||
		Reference in New Issue
	
	Block a user