mirror of
				https://github.com/TeaOSLab/EdgeAdmin.git
				synced 2025-11-04 13:10:26 +08:00 
			
		
		
		
	[用户节点]可以管理用户节点
This commit is contained in:
		@@ -1,3 +0,0 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
env GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o edge-admin main.go
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -9,13 +9,13 @@ import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var sharedUIConfig *systemconfigs.UIConfig = nil
 | 
			
		||||
var sharedUIConfig *systemconfigs.AdminUIConfig = nil
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	UISettingName = "adminUIConfig"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func LoadUIConfig() (*systemconfigs.UIConfig, error) {
 | 
			
		||||
func LoadUIConfig() (*systemconfigs.AdminUIConfig, error) {
 | 
			
		||||
	locker.Lock()
 | 
			
		||||
	defer locker.Unlock()
 | 
			
		||||
 | 
			
		||||
@@ -24,11 +24,11 @@ func LoadUIConfig() (*systemconfigs.UIConfig, error) {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	v := reflect.Indirect(reflect.ValueOf(config)).Interface().(systemconfigs.UIConfig)
 | 
			
		||||
	v := reflect.Indirect(reflect.ValueOf(config)).Interface().(systemconfigs.AdminUIConfig)
 | 
			
		||||
	return &v, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func UpdateUIConfig(uiConfig *systemconfigs.UIConfig) error {
 | 
			
		||||
func UpdateUIConfig(uiConfig *systemconfigs.AdminUIConfig) error {
 | 
			
		||||
	locker.Lock()
 | 
			
		||||
	defer locker.Unlock()
 | 
			
		||||
 | 
			
		||||
@@ -52,7 +52,7 @@ func UpdateUIConfig(uiConfig *systemconfigs.UIConfig) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func loadUIConfig() (*systemconfigs.UIConfig, error) {
 | 
			
		||||
func loadUIConfig() (*systemconfigs.AdminUIConfig, error) {
 | 
			
		||||
	if sharedUIConfig != nil {
 | 
			
		||||
		return sharedUIConfig, nil
 | 
			
		||||
	}
 | 
			
		||||
@@ -71,7 +71,7 @@ func loadUIConfig() (*systemconfigs.UIConfig, error) {
 | 
			
		||||
		return sharedUIConfig, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config := &systemconfigs.UIConfig{}
 | 
			
		||||
	config := &systemconfigs.AdminUIConfig{}
 | 
			
		||||
	err = json.Unmarshal(resp.ValueJSON, config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logs.Println("[UI_MANAGER]" + err.Error())
 | 
			
		||||
@@ -82,8 +82,8 @@ func loadUIConfig() (*systemconfigs.UIConfig, error) {
 | 
			
		||||
	return sharedUIConfig, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func defaultUIConfig() *systemconfigs.UIConfig {
 | 
			
		||||
	return &systemconfigs.UIConfig{
 | 
			
		||||
func defaultUIConfig() *systemconfigs.AdminUIConfig {
 | 
			
		||||
	return &systemconfigs.AdminUIConfig{
 | 
			
		||||
		ProductName:        "GoEdge",
 | 
			
		||||
		AdminSystemName:    "GoEdge管理员系统",
 | 
			
		||||
		ShowOpenSourceInfo: true,
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,10 @@ func (this *AdminNode) Run() {
 | 
			
		||||
	// 检查server配置
 | 
			
		||||
	err := this.checkServer()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logs.Println("[NODE]" + err.Error())
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -58,6 +62,7 @@ func (this *AdminNode) Run() {
 | 
			
		||||
	// 启动API节点
 | 
			
		||||
	this.startAPINode()
 | 
			
		||||
 | 
			
		||||
	// 启动Web服务
 | 
			
		||||
	TeaGo.NewServer(false).
 | 
			
		||||
		AccessLog(false).
 | 
			
		||||
		EndAll().
 | 
			
		||||
@@ -129,7 +134,7 @@ func (this *AdminNode) startAPINode() {
 | 
			
		||||
 | 
			
		||||
// 生成Secret
 | 
			
		||||
func (this *AdminNode) genSecret() string {
 | 
			
		||||
	tmpFile := os.TempDir() + "/edge-secret.tmp"
 | 
			
		||||
	tmpFile := os.TempDir() + "/edge-admin-secret.tmp"
 | 
			
		||||
	data, err := ioutil.ReadFile(tmpFile)
 | 
			
		||||
	if err == nil && len(data) == 32 {
 | 
			
		||||
		return string(data)
 | 
			
		||||
 
 | 
			
		||||
@@ -95,6 +95,10 @@ func (this *RPCClient) APINodeRPC() pb.APINodeServiceClient {
 | 
			
		||||
	return pb.NewAPINodeServiceClient(this.pickConn())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *RPCClient) UserNodeRPC() pb.UserNodeServiceClient {
 | 
			
		||||
	return pb.NewUserNodeServiceClient(this.pickConn())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *RPCClient) DBNodeRPC() pb.DBNodeServiceClient {
 | 
			
		||||
	return pb.NewDBNodeServiceClient(this.pickConn())
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ func init() {
 | 
			
		||||
		server.
 | 
			
		||||
			Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeSetting)).
 | 
			
		||||
			Helper(NewHelper()).
 | 
			
		||||
			Helper(settingutils.NewHelper("apiNodes")).
 | 
			
		||||
			Helper(settingutils.NewAdvancedHelper("apiNodes")).
 | 
			
		||||
			Prefix("/api").
 | 
			
		||||
			Get("", new(IndexAction)).
 | 
			
		||||
			GetPost("/node/createPopup", new(node.CreatePopupAction)).
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ func init() {
 | 
			
		||||
		server.
 | 
			
		||||
			Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeSetting)).
 | 
			
		||||
			Helper(new(Helper)).
 | 
			
		||||
			Helper(settingutils.NewHelper("dbNodes")).
 | 
			
		||||
			Helper(settingutils.NewAdvancedHelper("dbNodes")).
 | 
			
		||||
			Prefix("/db").
 | 
			
		||||
			Get("", new(IndexAction)).
 | 
			
		||||
			GetPost("/createPopup", new(CreatePopupAction)).
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								internal/web/actions/default/settings/advanced.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								internal/web/actions/default/settings/advanced.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
package settings
 | 
			
		||||
 | 
			
		||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
 | 
			
		||||
type AdvancedAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *AdvancedAction) Init() {
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *AdvancedAction) RunGet(params struct{}) {
 | 
			
		||||
	// 跳转到高级设置的第一个Tab
 | 
			
		||||
	this.RedirectURL("/settings/database")
 | 
			
		||||
}
 | 
			
		||||
@@ -11,7 +11,7 @@ func init() {
 | 
			
		||||
	TeaGo.BeforeStart(func(server *TeaGo.Server) {
 | 
			
		||||
		server.
 | 
			
		||||
			Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeSetting)).
 | 
			
		||||
			Helper(settingutils.NewHelper("database")).
 | 
			
		||||
			Helper(settingutils.NewAdvancedHelper("database")).
 | 
			
		||||
			Prefix("/settings/database").
 | 
			
		||||
			Get("", new(IndexAction)).
 | 
			
		||||
			GetPost("/update", new(UpdateAction)).
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@ func init() {
 | 
			
		||||
			Helper(NewHelper()).
 | 
			
		||||
			Prefix("/settings").
 | 
			
		||||
			Get("", new(IndexAction)).
 | 
			
		||||
			Get("/advanced", new(AdvancedAction)).
 | 
			
		||||
			EndAll()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
package settingutils
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AdvancedHelper struct {
 | 
			
		||||
	tab string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewAdvancedHelper(tab string) *AdvancedHelper {
 | 
			
		||||
	return &AdvancedHelper{
 | 
			
		||||
		tab: tab,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *AdvancedHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool) {
 | 
			
		||||
	goNext = true
 | 
			
		||||
 | 
			
		||||
	action := actionPtr.Object()
 | 
			
		||||
 | 
			
		||||
	// 左侧菜单
 | 
			
		||||
	action.Data["teaMenu"] = "settings"
 | 
			
		||||
	action.Data["teaSubMenu"] = "advanced"
 | 
			
		||||
 | 
			
		||||
	// 标签栏
 | 
			
		||||
	tabbar := actionutils.NewTabbar()
 | 
			
		||||
	var session = action.Session()
 | 
			
		||||
	var adminId = session.GetInt64("adminId")
 | 
			
		||||
	if configloaders.AllowModule(adminId, configloaders.AdminModuleCodeSetting) {
 | 
			
		||||
		tabbar.Add("数据库", "", "/settings/database", "", this.tab == "database")
 | 
			
		||||
		tabbar.Add("API节点", "", "/api", "", this.tab == "apiNodes")
 | 
			
		||||
		tabbar.Add("用户节点", "", "/settings/userNodes", "", this.tab == "userNodes")
 | 
			
		||||
		tabbar.Add("日志数据库", "", "/db", "", this.tab == "dbNodes")
 | 
			
		||||
	}
 | 
			
		||||
	actionutils.SetTabbar(actionPtr, tabbar)
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
@@ -32,9 +32,6 @@ func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool)
 | 
			
		||||
		tabbar.Add("Web服务", "", "/settings/server", "", this.tab == "server")
 | 
			
		||||
		tabbar.Add("界面设置", "", "/settings/ui", "", this.tab == "ui")
 | 
			
		||||
		tabbar.Add("安全设置", "", "/settings/security", "", this.tab == "security")
 | 
			
		||||
		tabbar.Add("数据库", "", "/settings/database", "", this.tab == "database")
 | 
			
		||||
		tabbar.Add("API节点", "", "/api", "", this.tab == "apiNodes")
 | 
			
		||||
		tabbar.Add("日志数据库", "", "/db", "", this.tab == "dbNodes")
 | 
			
		||||
		tabbar.Add("IP库", "", "/settings/ip-library", "", this.tab == "ipLibrary")
 | 
			
		||||
		tabbar.Add("备份", "", "/settings/backup", "", this.tab == "backup")
 | 
			
		||||
	}
 | 
			
		||||
							
								
								
									
										28
									
								
								internal/web/actions/default/settings/user-nodes/delete.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								internal/web/actions/default/settings/user-nodes/delete.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
package usernodes
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type DeleteAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *DeleteAction) RunPost(params struct {
 | 
			
		||||
	NodeId int64
 | 
			
		||||
}) {
 | 
			
		||||
	// TODO 检查权限
 | 
			
		||||
 | 
			
		||||
	_, err := this.RPC().UserNodeRPC().DeleteUserNode(this.AdminContext(), &pb.DeleteUserNodeRequest{NodeId: params.NodeId})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 创建日志
 | 
			
		||||
	defer this.CreateLog(oplogs.LevelInfo, "删除用户节点 %d", params.NodeId)
 | 
			
		||||
 | 
			
		||||
	this.Success()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								internal/web/actions/default/settings/user-nodes/helper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								internal/web/actions/default/settings/user-nodes/helper.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
package usernodes
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Helper struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewHelper() *Helper {
 | 
			
		||||
	return &Helper{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *Helper) BeforeAction(action *actions.ActionObject) {
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								internal/web/actions/default/settings/user-nodes/index.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								internal/web/actions/default/settings/user-nodes/index.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
package usernodes
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type IndexAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) Init() {
 | 
			
		||||
	this.Nav("", "node", "index")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) RunGet(params struct{}) {
 | 
			
		||||
	countResp, err := this.RPC().UserNodeRPC().CountAllEnabledUserNodes(this.AdminContext(), &pb.CountAllEnabledUserNodesRequest{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	count := countResp.Count
 | 
			
		||||
	page := this.NewPage(count)
 | 
			
		||||
	this.Data["page"] = page.AsHTML()
 | 
			
		||||
 | 
			
		||||
	nodeMaps := []maps.Map{}
 | 
			
		||||
	if count > 0 {
 | 
			
		||||
		nodesResp, err := this.RPC().UserNodeRPC().ListEnabledUserNodes(this.AdminContext(), &pb.ListEnabledUserNodesRequest{
 | 
			
		||||
			Offset: page.Offset,
 | 
			
		||||
			Size:   page.Size,
 | 
			
		||||
		})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			this.ErrorPage(err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, node := range nodesResp.Nodes {
 | 
			
		||||
			nodeMaps = append(nodeMaps, maps.Map{
 | 
			
		||||
				"id":          node.Id,
 | 
			
		||||
				"isOn":        node.IsOn,
 | 
			
		||||
				"name":        node.Name,
 | 
			
		||||
				"accessAddrs": node.AccessAddrs,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["nodes"] = nodeMaps
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								internal/web/actions/default/settings/user-nodes/init.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								internal/web/actions/default/settings/user-nodes/init.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
package usernodes
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/settingutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/user-nodes/node"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
 | 
			
		||||
	"github.com/iwind/TeaGo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	TeaGo.BeforeStart(func(server *TeaGo.Server) {
 | 
			
		||||
		server.
 | 
			
		||||
			Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeSetting)).
 | 
			
		||||
			Helper(NewHelper()).
 | 
			
		||||
			Helper(settingutils.NewAdvancedHelper("userNodes")).
 | 
			
		||||
			Prefix("/settings/userNodes").
 | 
			
		||||
			Get("", new(IndexAction)).
 | 
			
		||||
			GetPost("/node/createPopup", new(node.CreatePopupAction)).
 | 
			
		||||
			Post("/delete", new(DeleteAction)).
 | 
			
		||||
			EndAll()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
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()
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,143 @@
 | 
			
		||||
package node
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
 | 
			
		||||
	"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"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type CreatePopupAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *CreatePopupAction) Init() {
 | 
			
		||||
	this.Nav("", "node", "create")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *CreatePopupAction) RunGet(params struct{}) {
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *CreatePopupAction) RunPost(params struct {
 | 
			
		||||
	Name            string
 | 
			
		||||
	Description     string
 | 
			
		||||
	ListensJSON     []byte
 | 
			
		||||
	CertIdsJSON     []byte
 | 
			
		||||
	AccessAddrsJSON []byte
 | 
			
		||||
	IsOn            bool
 | 
			
		||||
 | 
			
		||||
	Must *actions.Must
 | 
			
		||||
}) {
 | 
			
		||||
	params.Must.
 | 
			
		||||
		Field("name", params.Name).
 | 
			
		||||
		Require("请输入用户节点名称")
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	createResp, err := this.RPC().UserNodeRPC().CreateUserNode(this.AdminContext(), &pb.CreateUserNodeRequest{
 | 
			
		||||
		Name:            params.Name,
 | 
			
		||||
		Description:     params.Description,
 | 
			
		||||
		HttpJSON:        httpJSON,
 | 
			
		||||
		HttpsJSON:       httpsJSON,
 | 
			
		||||
		AccessAddrsJSON: params.AccessAddrsJSON,
 | 
			
		||||
		IsOn:            params.IsOn,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 创建日志
 | 
			
		||||
	defer this.CreateLog(oplogs.LevelInfo, "创建用户节点 %d", createResp.NodeId)
 | 
			
		||||
 | 
			
		||||
	this.Success()
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,21 @@
 | 
			
		||||
package node
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
	"net/http"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Helper struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewHelper() *Helper {
 | 
			
		||||
	return &Helper{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *Helper) BeforeAction(action *actions.ActionObject) (goNext bool) {
 | 
			
		||||
	if action.Request.Method != http.MethodGet {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										102
									
								
								internal/web/actions/default/settings/user-nodes/node/index.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								internal/web/actions/default/settings/user-nodes/node/index.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
			
		||||
package node
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"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/maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type IndexAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) Init() {
 | 
			
		||||
	this.Nav("", "", "index")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) RunGet(params struct {
 | 
			
		||||
	NodeId int64
 | 
			
		||||
}) {
 | 
			
		||||
	nodeResp, err := this.RPC().UserNodeRPC().FindEnabledUserNode(this.AdminContext(), &pb.FindEnabledUserNodeRequest{NodeId: params.NodeId})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	node := nodeResp.Node
 | 
			
		||||
	if node == nil {
 | 
			
		||||
		this.NotFound("userNode", params.NodeId)
 | 
			
		||||
		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,
 | 
			
		||||
		"isOn":        node.IsOn,
 | 
			
		||||
		"listens":     listens,
 | 
			
		||||
		"accessAddrs": accessAddrs,
 | 
			
		||||
		"hasHTTPS":    sslPolicyId > 0,
 | 
			
		||||
		"certs":       certs,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,29 @@
 | 
			
		||||
package node
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/settingutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
 | 
			
		||||
	"github.com/iwind/TeaGo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	TeaGo.BeforeStart(func(server *TeaGo.Server) {
 | 
			
		||||
		server.
 | 
			
		||||
			Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeSetting)).
 | 
			
		||||
			Helper(settingutils.NewAdvancedHelper("userNodes")).
 | 
			
		||||
			Prefix("/settings/userNodes/node").
 | 
			
		||||
 | 
			
		||||
			// 这里不受Helper的约束
 | 
			
		||||
			GetPost("/createAddrPopup", new(CreateAddrPopupAction)).
 | 
			
		||||
			GetPost("/updateAddrPopup", new(UpdateAddrPopupAction)).
 | 
			
		||||
 | 
			
		||||
			// 节点相关
 | 
			
		||||
			Helper(NewHelper()).
 | 
			
		||||
			Get("", new(IndexAction)).
 | 
			
		||||
			GetPost("/update", new(UpdateAction)).
 | 
			
		||||
			Get("/install", new(InstallAction)).
 | 
			
		||||
 | 
			
		||||
			EndAll()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,57 @@
 | 
			
		||||
package node
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type InstallAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *InstallAction) Init() {
 | 
			
		||||
	this.Nav("", "", "install")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *InstallAction) RunGet(params struct {
 | 
			
		||||
	NodeId int64
 | 
			
		||||
}) {
 | 
			
		||||
	// 用户节点信息
 | 
			
		||||
	nodeResp, err := this.RPC().UserNodeRPC().FindEnabledUserNode(this.AdminContext(), &pb.FindEnabledUserNodeRequest{NodeId: params.NodeId})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	node := nodeResp.Node
 | 
			
		||||
	if node == nil {
 | 
			
		||||
		this.NotFound("userNode", params.NodeId)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Data["node"] = maps.Map{
 | 
			
		||||
		"id":       node.Id,
 | 
			
		||||
		"name":     node.Name,
 | 
			
		||||
		"uniqueId": node.UniqueId,
 | 
			
		||||
		"secret":   node.Secret,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// API节点列表
 | 
			
		||||
	apiNodesResp, err := this.RPC().APINodeRPC().FindAllEnabledAPINodes(this.AdminContext(), &pb.FindAllEnabledAPINodesRequest{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	apiNodes := apiNodesResp.Nodes
 | 
			
		||||
	apiEndpoints := []string{}
 | 
			
		||||
	for _, apiNode := range apiNodes {
 | 
			
		||||
		if !apiNode.IsOn {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		apiEndpoints = append(apiEndpoints, apiNode.AccessAddrs...)
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										240
									
								
								internal/web/actions/default/settings/user-nodes/node/update.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								internal/web/actions/default/settings/user-nodes/node/update.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,240 @@
 | 
			
		||||
package node
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
 | 
			
		||||
	"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"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type UpdateAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *UpdateAction) Init() {
 | 
			
		||||
	this.Nav("", "", "update")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *UpdateAction) RunGet(params struct {
 | 
			
		||||
	NodeId int64
 | 
			
		||||
}) {
 | 
			
		||||
	nodeResp, err := this.RPC().UserNodeRPC().FindEnabledUserNode(this.AdminContext(), &pb.FindEnabledUserNodeRequest{
 | 
			
		||||
		NodeId: params.NodeId,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	node := nodeResp.Node
 | 
			
		||||
	if node == nil {
 | 
			
		||||
		this.WriteString("要操作的节点不存在")
 | 
			
		||||
		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,
 | 
			
		||||
		"isOn":        node.IsOn,
 | 
			
		||||
		"listens":     listens,
 | 
			
		||||
		"certs":       certs,
 | 
			
		||||
		"sslPolicyId": sslPolicyId,
 | 
			
		||||
		"accessAddrs": accessAddrs,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 保存基础设置
 | 
			
		||||
func (this *UpdateAction) RunPost(params struct {
 | 
			
		||||
	NodeId          int64
 | 
			
		||||
	Name            string
 | 
			
		||||
	SslPolicyId     int64
 | 
			
		||||
	ListensJSON     []byte
 | 
			
		||||
	CertIdsJSON     []byte
 | 
			
		||||
	AccessAddrsJSON []byte
 | 
			
		||||
	Description     string
 | 
			
		||||
	IsOn            bool
 | 
			
		||||
 | 
			
		||||
	Must *actions.Must
 | 
			
		||||
}) {
 | 
			
		||||
	params.Must.
 | 
			
		||||
		Field("name", params.Name).
 | 
			
		||||
		Require("请输入用户节点名称")
 | 
			
		||||
 | 
			
		||||
	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().UserNodeRPC().UpdateUserNode(this.AdminContext(), &pb.UpdateUserNodeRequest{
 | 
			
		||||
		NodeId:          params.NodeId,
 | 
			
		||||
		Name:            params.Name,
 | 
			
		||||
		Description:     params.Description,
 | 
			
		||||
		HttpJSON:        httpJSON,
 | 
			
		||||
		HttpsJSON:       httpsJSON,
 | 
			
		||||
		AccessAddrsJSON: params.AccessAddrsJSON,
 | 
			
		||||
		IsOn:            params.IsOn,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 创建日志
 | 
			
		||||
	defer this.CreateLog(oplogs.LevelInfo, "修改用户节点 %d", params.NodeId)
 | 
			
		||||
 | 
			
		||||
	this.Success()
 | 
			
		||||
}
 | 
			
		||||
@@ -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()
 | 
			
		||||
}
 | 
			
		||||
@@ -226,6 +226,13 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
 | 
			
		||||
			"module": configloaders.AdminModuleCodeSetting,
 | 
			
		||||
			"name":   "系统设置",
 | 
			
		||||
			"icon":   "setting",
 | 
			
		||||
			"subItems": []maps.Map{
 | 
			
		||||
				{
 | 
			
		||||
					"name": "高级设置",
 | 
			
		||||
					"url":  "/settings/advanced",
 | 
			
		||||
					"code": "advanced",
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -85,6 +85,7 @@ import (
 | 
			
		||||
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/server"
 | 
			
		||||
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/ui"
 | 
			
		||||
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/upgrade"
 | 
			
		||||
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/user-nodes"
 | 
			
		||||
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/setup"
 | 
			
		||||
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ui"
 | 
			
		||||
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/users"
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ Vue.component("network-addresses-view", {
 | 
			
		||||
	props: ["v-addresses"],
 | 
			
		||||
	template: `<div>
 | 
			
		||||
	<div class="ui label tiny basic" v-if="vAddresses != null" v-for="addr in vAddresses">
 | 
			
		||||
		{{addr.protocol}}://{{addr.host}}:{{addr.portRange}}
 | 
			
		||||
		{{addr.protocol}}://<span v-if="addr.host.length > 0">{{addr.host}}</span><span v-else>*</span>:{{addr.portRange}}
 | 
			
		||||
	</div>
 | 
			
		||||
</div>`
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										35
									
								
								web/views/@default/settings/user-nodes/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								web/views/@default/settings/user-nodes/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
{$layout}
 | 
			
		||||
 | 
			
		||||
<first-menu>
 | 
			
		||||
	<a href="" class="item" @click.prevent="createNode()">[添加节点]</a>
 | 
			
		||||
</first-menu>
 | 
			
		||||
 | 
			
		||||
<p class="comment" v-if="nodes.length == 0">暂时还没有节点。</p>
 | 
			
		||||
 | 
			
		||||
<table class="ui table selectable celled" v-if="nodes.length > 0">
 | 
			
		||||
	<thead>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<th>节点名称</th>
 | 
			
		||||
			<th>访问地址</th>
 | 
			
		||||
			<th class="center width10">状态</th>
 | 
			
		||||
			<th class="two op">操作</th>
 | 
			
		||||
		</tr>
 | 
			
		||||
	</thead>
 | 
			
		||||
	<tr v-for="node in nodes">
 | 
			
		||||
		<td>{{node.name}}</td>
 | 
			
		||||
		<td>
 | 
			
		||||
			<div v-if="node.accessAddrs != null && node.accessAddrs.length > 0">
 | 
			
		||||
				<span class="ui label tiny basic" v-for="addr in node.accessAddrs">{{addr}}</span>
 | 
			
		||||
			</div>
 | 
			
		||||
		</td>
 | 
			
		||||
		<td class="center">
 | 
			
		||||
			<label-on :v-is-on="node.isOn"></label-on>
 | 
			
		||||
		</td>
 | 
			
		||||
		<td>
 | 
			
		||||
			<a :href="'/settings/userNodes/node?nodeId=' + node.id">详情</a>  
 | 
			
		||||
			<a href="" @click.prevent="deleteNode(node.id)">删除</a>
 | 
			
		||||
		</td>
 | 
			
		||||
	</tr>
 | 
			
		||||
</table>
 | 
			
		||||
 | 
			
		||||
<div class="page" v-html="page"></div>
 | 
			
		||||
							
								
								
									
										26
									
								
								web/views/@default/settings/user-nodes/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								web/views/@default/settings/user-nodes/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	// 创建节点
 | 
			
		||||
	this.createNode = function () {
 | 
			
		||||
		teaweb.popup("/settings/userNodes/node/createPopup", {
 | 
			
		||||
			width: "50em",
 | 
			
		||||
			height: "30em",
 | 
			
		||||
			callback: function () {
 | 
			
		||||
				teaweb.success("保存成功", function () {
 | 
			
		||||
					teaweb.reload()
 | 
			
		||||
				})
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 删除节点
 | 
			
		||||
	this.deleteNode = function (nodeId) {
 | 
			
		||||
		let that = this
 | 
			
		||||
		teaweb.confirm("确定要删除此节点吗?", function () {
 | 
			
		||||
			that.$post("/settings/userNodes/delete")
 | 
			
		||||
				.params({
 | 
			
		||||
					nodeId: nodeId
 | 
			
		||||
				})
 | 
			
		||||
				.refresh()
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										7
									
								
								web/views/@default/settings/user-nodes/node/@menu.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								web/views/@default/settings/user-nodes/node/@menu.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
<first-menu>
 | 
			
		||||
	<menu-item href="/settings/userNodes">节点列表</menu-item>
 | 
			
		||||
	<span class="item">|</span>
 | 
			
		||||
	<menu-item :href="'/settings/userNodes/node?nodeId=' + node.id" code="index">"{{node.name}}"详情</menu-item>
 | 
			
		||||
	<menu-item :href="'/settings/userNodes/node/install?nodeId=' + node.id" code="install">安装节点</menu-item>
 | 
			
		||||
	<menu-item :href="'/settings/userNodes/node/update?nodeId=' + node.id" code="update">修改节点</menu-item>
 | 
			
		||||
</first-menu>
 | 
			
		||||
@@ -0,0 +1,24 @@
 | 
			
		||||
{$layout "layout_popup"}
 | 
			
		||||
 | 
			
		||||
<h3>添加访问地址</h3>
 | 
			
		||||
<form class="ui form" method="post" 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>
 | 
			
		||||
							
								
								
									
										55
									
								
								web/views/@default/settings/user-nodes/node/createPopup.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								web/views/@default/settings/user-nodes/node/createPopup.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
{$layout "layout_popup"}
 | 
			
		||||
 | 
			
		||||
<h3>添加用户节点</h3>
 | 
			
		||||
<form class="ui form" method="post" data-tea-action="$" data-tea-success="success">
 | 
			
		||||
	<table class="ui table selectable definition">
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td class="title">节点名称 *</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<input type="text" name="name" maxlength="100" ref="focus"/>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td>进程监听端口 *</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<network-addresses-box :v-name="'listensJSON'" :v-server-type="'httpWeb'" @change="changeListens"></network-addresses-box>
 | 
			
		||||
				<p class="comment">用户节点进程监听的网络端口。</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>
 | 
			
		||||
				<api-node-addresses-box :v-name="'accessAddrsJSON'"></api-node-addresses-box>
 | 
			
		||||
				<p class="comment">可以公开访问的网络地址。</p>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td colspan="2"><more-options-indicator></more-options-indicator></td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tbody v-show="moreOptionsVisible">
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>描述</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<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>
 | 
			
		||||
</form>
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.hasHTTPS = false
 | 
			
		||||
	this.changeListens = function (addrs) {
 | 
			
		||||
		this.hasHTTPS = addrs.$any(function (k, v) {
 | 
			
		||||
			return v.protocol == "https"
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										44
									
								
								web/views/@default/settings/user-nodes/node/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								web/views/@default/settings/user-nodes/node/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
{$layout}
 | 
			
		||||
{$template "menu"}
 | 
			
		||||
 | 
			
		||||
<table class="ui table selectable definition">
 | 
			
		||||
	<tr>
 | 
			
		||||
		<td class="title">节点名称</td>
 | 
			
		||||
		<td>
 | 
			
		||||
			{{node.name}}
 | 
			
		||||
		</td>
 | 
			
		||||
	</tr>
 | 
			
		||||
	<tr>
 | 
			
		||||
		<td>状态</td>
 | 
			
		||||
		<td>
 | 
			
		||||
			<label-on :v-is-on="node.isOn"></label-on>
 | 
			
		||||
		</td>
 | 
			
		||||
	</tr>
 | 
			
		||||
	<tr>
 | 
			
		||||
		<td>进程监听端口</td>
 | 
			
		||||
		<td>
 | 
			
		||||
			<network-addresses-view :v-addresses="node.listens"></network-addresses-view>
 | 
			
		||||
			<p class="comment">用户节点进程监听的网络端口。</p>
 | 
			
		||||
		</td>
 | 
			
		||||
	</tr>
 | 
			
		||||
	<tr v-if="node.hasHTTPS">
 | 
			
		||||
		<td>HTTPS证书</td>
 | 
			
		||||
		<td>
 | 
			
		||||
			<ssl-certs-view :v-certs="node.certs"></ssl-certs-view>
 | 
			
		||||
		</td>
 | 
			
		||||
	</tr>
 | 
			
		||||
	<tr>
 | 
			
		||||
		<td>外部访问地址</td>
 | 
			
		||||
		<td>
 | 
			
		||||
			<network-addresses-view :v-addresses="node.accessAddrs"></network-addresses-view>
 | 
			
		||||
			<p class="comment">可以公开访问的网络地址。</p>
 | 
			
		||||
		</td>
 | 
			
		||||
	</tr>
 | 
			
		||||
	<tr>
 | 
			
		||||
		<td>描述</td>
 | 
			
		||||
		<td>
 | 
			
		||||
			<span v-if="node.description.length > 0">{{node.description}}</span>
 | 
			
		||||
			<span v-else class="disabled">暂时还没有描述。</span>
 | 
			
		||||
		</td>
 | 
			
		||||
	</tr>
 | 
			
		||||
</table>
 | 
			
		||||
							
								
								
									
										23
									
								
								web/views/@default/settings/user-nodes/node/install.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								web/views/@default/settings/user-nodes/node/install.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
{$layout}
 | 
			
		||||
{$template "menu"}
 | 
			
		||||
 | 
			
		||||
<h3>安装步骤</h3>
 | 
			
		||||
<ol class="ui list">
 | 
			
		||||
	<li>按照下面的配置信息替换<code-label>configs/api.yaml</code-label>内容</li>
 | 
			
		||||
	<li>使用<code-label>bin/edge-user start</code-label>启动节点</li>
 | 
			
		||||
	<li>可以在<code-label>logs/run.log</code-label>中查看启动是否有异常</li>
 | 
			
		||||
</ol>
 | 
			
		||||
 | 
			
		||||
<div class="ui divider"></div>
 | 
			
		||||
<h3>配置信息</h3>
 | 
			
		||||
<table class="ui table definition selectable">
 | 
			
		||||
	<tr>
 | 
			
		||||
		<td class="title">configs/api.yaml<em><br/><download-link :v-element="'api-code'" :v-file="'api.yaml'">[下载]</download-link></em></td>
 | 
			
		||||
		<td>
 | 
			
		||||
			<pre id="api-code">rpc:
 | 
			
		||||
  endpoints: [ {{apiEndpoints}} ]
 | 
			
		||||
nodeId: "{{node.uniqueId}}"
 | 
			
		||||
secret: "{{node.secret}}"</pre>
 | 
			
		||||
		</td>
 | 
			
		||||
	</tr>
 | 
			
		||||
</table>
 | 
			
		||||
							
								
								
									
										58
									
								
								web/views/@default/settings/user-nodes/node/update.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								web/views/@default/settings/user-nodes/node/update.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
{$layout}
 | 
			
		||||
 | 
			
		||||
{$template "menu"}
 | 
			
		||||
 | 
			
		||||
<form method="post" 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>
 | 
			
		||||
			<td>
 | 
			
		||||
				<input type="text" name="name" maxlength="100" ref="focus" v-model="node.name"/>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td>进程监听端口 *</td>
 | 
			
		||||
			<td>
 | 
			
		||||
				<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>
 | 
			
		||||
				<api-node-addresses-box :v-name="'accessAddrsJSON'" :v-addrs="node.accessAddrs"></api-node-addresses-box>
 | 
			
		||||
				<p class="comment">边缘节点和管理平台等外部节点访问API节点的网络地址。</p>
 | 
			
		||||
			</td>
 | 
			
		||||
		</tr>
 | 
			
		||||
 | 
			
		||||
		<tr>
 | 
			
		||||
			<td colspan="2"><more-options-indicator></more-options-indicator></td>
 | 
			
		||||
		</tr>
 | 
			
		||||
		<tbody v-show="moreOptionsVisible">
 | 
			
		||||
			<tr>
 | 
			
		||||
				<td>描述</td>
 | 
			
		||||
				<td>
 | 
			
		||||
					<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>
 | 
			
		||||
</form>
 | 
			
		||||
							
								
								
									
										12
									
								
								web/views/@default/settings/user-nodes/node/update.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								web/views/@default/settings/user-nodes/node/update.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.success = NotifySuccess("保存成功", "/settings/userNodes/node?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"
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
@@ -0,0 +1,24 @@
 | 
			
		||||
{$layout "layout_popup"}
 | 
			
		||||
 | 
			
		||||
<h3>修改访问地址</h3>
 | 
			
		||||
<form method="post" 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>
 | 
			
		||||
@@ -0,0 +1,5 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	let addr = window.parent.UPDATING_ADDR
 | 
			
		||||
	this.protocol = addr.protocol
 | 
			
		||||
	this.addr = addr.host + ":" + addr.portRange
 | 
			
		||||
})
 | 
			
		||||
		Reference in New Issue
	
	Block a user