Compare commits
121 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15a11c384b | ||
|
|
57b8496d89 | ||
|
|
7bbe44f5d2 | ||
|
|
ac11ab0431 | ||
|
|
12e352964c | ||
|
|
7daefc4384 | ||
|
|
29541becd0 | ||
|
|
ef6dc82f88 | ||
|
|
6d66d93180 | ||
|
|
3ded17b920 | ||
|
|
d35651f570 | ||
|
|
235300d034 | ||
|
|
2f7ebf5166 | ||
|
|
4819cc87c6 | ||
|
|
c5da383d1e | ||
|
|
2da17329fa | ||
|
|
70d84acf76 | ||
|
|
fef99a0023 | ||
|
|
76d0935e8f | ||
|
|
42dfe5ada9 | ||
|
|
ef136c25e1 | ||
|
|
4251635a8a | ||
|
|
13f00104dd | ||
|
|
b0b82b29c1 | ||
|
|
e0d43ad3d9 | ||
|
|
ae15115af7 | ||
|
|
a2890c6cb0 | ||
|
|
2b00ece07f | ||
|
|
2e3c34571f | ||
|
|
b8b10b5176 | ||
|
|
e6e62bbd24 | ||
|
|
05e9bbf1d6 | ||
|
|
bf94c2395f | ||
|
|
4a749ca345 | ||
|
|
80ffe6c9a3 | ||
|
|
5414b5a8f9 | ||
|
|
e3ba85a326 | ||
|
|
154fa69dbb | ||
|
|
76c44973e9 | ||
|
|
26fdc82cc1 | ||
|
|
dcc587182c | ||
|
|
7cee1ff5ff | ||
|
|
78b8e3bf0b | ||
|
|
bd4c014c12 | ||
|
|
daa263cd68 | ||
|
|
e2965d39af | ||
|
|
8279d15ebb | ||
|
|
9731fa35d8 | ||
|
|
53be4db22b | ||
|
|
0202fa2ca3 | ||
|
|
d5262b5474 | ||
|
|
cb2e1d54c2 | ||
|
|
6392297a27 | ||
|
|
6001d4eba3 | ||
|
|
79588e4bbc | ||
|
|
2b21c38382 | ||
|
|
481d25845e | ||
|
|
e0f8bfe283 | ||
|
|
d2ecb01358 | ||
|
|
316e793b1e | ||
|
|
6df6809ab3 | ||
|
|
c71f892601 | ||
|
|
d0b5a16ce7 | ||
|
|
84638d3228 | ||
|
|
bb21a2aa5f | ||
|
|
c37c948129 | ||
|
|
5155476dd7 | ||
|
|
7ef4f60309 | ||
|
|
b0865cbbdc | ||
|
|
990c1070e2 | ||
|
|
65bdd413eb | ||
|
|
60fa35eb73 | ||
|
|
32cfd5c233 | ||
|
|
7852495527 | ||
|
|
3679a78f47 | ||
|
|
6b21568408 | ||
|
|
04a5aa41d7 | ||
|
|
fea1a2199c | ||
|
|
9c8492efb9 | ||
|
|
20b89a8ddd | ||
|
|
5a8e281fb1 | ||
|
|
a9bb413199 | ||
|
|
428d8ab1b1 | ||
|
|
c2675bcdb6 | ||
|
|
1fe228e4c0 | ||
|
|
c5a6497f10 | ||
|
|
f25a82585f | ||
|
|
01209b66ac | ||
|
|
4e19817d6f | ||
|
|
a48adff8ac | ||
|
|
ab3b32fda1 | ||
|
|
cafab78ab4 | ||
|
|
2d497dee7d | ||
|
|
280ecd9aea | ||
|
|
3a980a3bc0 | ||
|
|
556a5bdd4e | ||
|
|
eca26a345f | ||
|
|
eacff7232d | ||
|
|
3c071db207 | ||
|
|
6609c56063 | ||
|
|
f7ae3de914 | ||
|
|
d82bc4e77e | ||
|
|
31e1df0afd | ||
|
|
700e9236f9 | ||
|
|
ee1e62aff0 | ||
|
|
aa0c38d66f | ||
|
|
4e4d9e33f0 | ||
|
|
f78daa98bc | ||
|
|
dad8802fb0 | ||
|
|
529b7041e7 | ||
|
|
5de1eecf92 | ||
|
|
08ee301f89 | ||
|
|
4154904b21 | ||
|
|
79282809e3 | ||
|
|
108c2533c2 | ||
|
|
fd7309cd17 | ||
|
|
c5f871edf6 | ||
|
|
3f2d2b238d | ||
|
|
e6a30b99d3 | ||
|
|
08ce2b7799 | ||
|
|
dbe7336f32 |
BIN
cmd/edge-admin/edge-admin
Executable file
BIN
cmd/edge-admin/edge-admin
Executable file
Binary file not shown.
@@ -7,17 +7,20 @@ import (
|
|||||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/gen"
|
"github.com/TeaOSLab/EdgeAdmin/internal/gen"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/nodes"
|
"github.com/TeaOSLab/EdgeAdmin/internal/nodes"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web"
|
||||||
_ "github.com/iwind/TeaGo/bootstrap"
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"github.com/iwind/gosock/pkg/gosock"
|
"github.com/iwind/gosock/pkg/gosock"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := apps.NewAppCmd().
|
var app = apps.NewAppCmd().
|
||||||
Version(teaconst.Version).
|
Version(teaconst.Version).
|
||||||
Product(teaconst.ProductName).
|
Product(teaconst.ProductName).
|
||||||
Usage(teaconst.ProcessName+" [-v|start|stop|restart|service|daemon|reset|recover|demo]").
|
Usage(teaconst.ProcessName+" [-v|start|stop|restart|service|daemon|reset|recover|demo|upgrade]").
|
||||||
Usage(teaconst.ProcessName+" [dev|prod]").
|
Usage(teaconst.ProcessName+" [dev|prod]").
|
||||||
Option("-h", "show this help").
|
Option("-h", "show this help").
|
||||||
Option("-v", "show version").
|
Option("-v", "show version").
|
||||||
@@ -30,7 +33,8 @@ func main() {
|
|||||||
Option("recover", "enter recovery mode").
|
Option("recover", "enter recovery mode").
|
||||||
Option("demo", "switch to demo mode").
|
Option("demo", "switch to demo mode").
|
||||||
Option("dev", "switch to 'dev' mode").
|
Option("dev", "switch to 'dev' mode").
|
||||||
Option("prod", "switch to 'prod' mode")
|
Option("prod", "switch to 'prod' mode").
|
||||||
|
Option("upgrade", "upgrade from official site")
|
||||||
|
|
||||||
app.On("daemon", func() {
|
app.On("daemon", func() {
|
||||||
nodes.NewAdminNode().Daemon()
|
nodes.NewAdminNode().Daemon()
|
||||||
@@ -115,8 +119,42 @@ func main() {
|
|||||||
fmt.Println("switch to '" + env + "' ok")
|
fmt.Println("switch to '" + env + "' ok")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
app.On("upgrade", func() {
|
||||||
|
var manager = utils.NewUpgradeManager("admin")
|
||||||
|
log.Println("checking latest version ...")
|
||||||
|
var ticker = time.NewTicker(1 * time.Second)
|
||||||
|
go func() {
|
||||||
|
var lastProgress float32 = 0
|
||||||
|
var isStarted = false
|
||||||
|
for range ticker.C {
|
||||||
|
if manager.IsDownloading() {
|
||||||
|
if !isStarted {
|
||||||
|
log.Println("start downloading v" + manager.NewVersion() + " ...")
|
||||||
|
isStarted = true
|
||||||
|
}
|
||||||
|
var progress = manager.Progress()
|
||||||
|
if progress >= 0 {
|
||||||
|
if progress == 0 || progress == 1 || progress-lastProgress >= 0.1 {
|
||||||
|
lastProgress = progress
|
||||||
|
log.Println(fmt.Sprintf("%.2f%%", manager.Progress()*100))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
err := manager.Start()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("upgrade failed: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Println("finished!")
|
||||||
|
log.Println("restarting ...")
|
||||||
|
app.RunRestart()
|
||||||
|
})
|
||||||
app.Run(func() {
|
app.Run(func() {
|
||||||
adminNode := nodes.NewAdminNode()
|
var adminNode = nodes.NewAdminNode()
|
||||||
adminNode.Run()
|
adminNode.Run()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ func (this *AppCmd) On(arg string, callback func()) {
|
|||||||
// Run 运行
|
// Run 运行
|
||||||
func (this *AppCmd) Run(main func()) {
|
func (this *AppCmd) Run(main func()) {
|
||||||
// 获取参数
|
// 获取参数
|
||||||
args := os.Args[1:]
|
var args = os.Args[1:]
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
switch args[0] {
|
switch args[0] {
|
||||||
case "-v", "version", "-version", "--version":
|
case "-v", "version", "-version", "--version":
|
||||||
@@ -139,7 +139,7 @@ func (this *AppCmd) Run(main func()) {
|
|||||||
this.runStop()
|
this.runStop()
|
||||||
return
|
return
|
||||||
case "restart":
|
case "restart":
|
||||||
this.runRestart()
|
this.RunRestart()
|
||||||
return
|
return
|
||||||
case "status":
|
case "status":
|
||||||
this.runStatus()
|
this.runStatus()
|
||||||
@@ -160,7 +160,7 @@ func (this *AppCmd) Run(main func()) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 日志
|
// 日志
|
||||||
writer := new(LogWriter)
|
var writer = new(LogWriter)
|
||||||
writer.Init()
|
writer.Init()
|
||||||
logs.SetWriter(writer)
|
logs.SetWriter(writer)
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ func (this *AppCmd) runStop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 重启
|
// 重启
|
||||||
func (this *AppCmd) runRestart() {
|
func (this *AppCmd) RunRestart() {
|
||||||
this.runStop()
|
this.runStop()
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
this.runStart()
|
this.runStart()
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ const (
|
|||||||
AdminModuleCodePlan AdminModuleCode = "plan" // 套餐
|
AdminModuleCodePlan AdminModuleCode = "plan" // 套餐
|
||||||
AdminModuleCodeLog AdminModuleCode = "log" // 日志
|
AdminModuleCodeLog AdminModuleCode = "log" // 日志
|
||||||
AdminModuleCodeSetting AdminModuleCode = "setting" // 设置
|
AdminModuleCodeSetting AdminModuleCode = "setting" // 设置
|
||||||
|
AdminModuleCodeTicket AdminModuleCode = "ticket" // 工单
|
||||||
AdminModuleCodeCommon AdminModuleCode = "common" // 只要登录就可以访问的模块
|
AdminModuleCodeCommon AdminModuleCode = "common" // 只要登录就可以访问的模块
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -159,7 +160,7 @@ func UpdateAdminTheme(adminId int64, theme string) {
|
|||||||
|
|
||||||
// AllModuleMaps 所有权限列表
|
// AllModuleMaps 所有权限列表
|
||||||
func AllModuleMaps() []maps.Map {
|
func AllModuleMaps() []maps.Map {
|
||||||
m := []maps.Map{
|
var m = []maps.Map{
|
||||||
{
|
{
|
||||||
"name": "看板",
|
"name": "看板",
|
||||||
"code": AdminModuleCodeDashboard,
|
"code": AdminModuleCodeDashboard,
|
||||||
@@ -204,11 +205,24 @@ func AllModuleMaps() []maps.Map {
|
|||||||
"code": AdminModuleCodeFinance,
|
"code": AdminModuleCodeFinance,
|
||||||
"url": "/finance",
|
"url": "/finance",
|
||||||
},
|
},
|
||||||
{
|
}...)
|
||||||
"name": "套餐管理",
|
|
||||||
"code": AdminModuleCodePlan,
|
if teaconst.IsPlus {
|
||||||
"url": "/plans",
|
m = append(m, []maps.Map{
|
||||||
},
|
{
|
||||||
|
"name": "套餐管理",
|
||||||
|
"code": AdminModuleCodePlan,
|
||||||
|
"url": "/plans",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "工单系统",
|
||||||
|
"code": AdminModuleCodeTicket,
|
||||||
|
"url": "/tickets",
|
||||||
|
},
|
||||||
|
}...)
|
||||||
|
}
|
||||||
|
|
||||||
|
m = append(m, []maps.Map{
|
||||||
{
|
{
|
||||||
"name": "日志审计",
|
"name": "日志审计",
|
||||||
"code": AdminModuleCodeLog,
|
"code": AdminModuleCodeLog,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestLoadAdminModuleMapping(t *testing.T) {
|
func TestLoadAdminModuleMapping(t *testing.T) {
|
||||||
m, err := LoadAdminModuleMapping()
|
m, err := loadAdminModuleMapping()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,15 @@ func LoadAdminUIConfig() (*systemconfigs.AdminUIConfig, error) {
|
|||||||
return &v, nil
|
return &v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReloadAdminUIConfig() error {
|
||||||
|
locker.Lock()
|
||||||
|
defer locker.Unlock()
|
||||||
|
|
||||||
|
sharedAdminUIConfig = nil
|
||||||
|
_, err := loadAdminUIConfig()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func UpdateAdminUIConfig(uiConfig *systemconfigs.AdminUIConfig) error {
|
func UpdateAdminUIConfig(uiConfig *systemconfigs.AdminUIConfig) error {
|
||||||
locker.Lock()
|
locker.Lock()
|
||||||
defer locker.Unlock()
|
defer locker.Unlock()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
func TestLoadUIConfig(t *testing.T) {
|
func TestLoadUIConfig(t *testing.T) {
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
before := time.Now()
|
before := time.Now()
|
||||||
config, err := LoadUIConfig()
|
config, err := LoadAdminUIConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@ func TestLoadUIConfig(t *testing.T) {
|
|||||||
|
|
||||||
func TestLoadUIConfig2(t *testing.T) {
|
func TestLoadUIConfig2(t *testing.T) {
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
config, err := LoadUIConfig()
|
config, err := LoadAdminUIConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
@@ -34,7 +33,7 @@ func LoadAPIConfig() (*APIConfig, error) {
|
|||||||
var data []byte
|
var data []byte
|
||||||
var err error
|
var err error
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
data, err = ioutil.ReadFile(path)
|
data, err = os.ReadFile(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if path == localFile {
|
if path == localFile {
|
||||||
isFromLocal = true
|
isFromLocal = true
|
||||||
@@ -54,7 +53,7 @@ func LoadAPIConfig() (*APIConfig, error) {
|
|||||||
|
|
||||||
if !isFromLocal {
|
if !isFromLocal {
|
||||||
// 恢复文件
|
// 恢复文件
|
||||||
_ = ioutil.WriteFile(localFile, data, 0666)
|
_ = os.WriteFile(localFile, data, 0666)
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
@@ -110,41 +109,48 @@ func (this *APIConfig) WriteFile(path string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(path, data, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// 写入 ~/ 和 /etc/ 目录,因为是备份需要,所以不需要提示错误信息
|
// 写入 ~/ 和 /etc/ 目录,因为是备份需要,所以不需要提示错误信息
|
||||||
// 写入 ~/.edge-admin/
|
// 写入 ~/.edge-admin/
|
||||||
filename := filepath.Base(path)
|
// 这个用来判断用户是否为重装,所以比较重要
|
||||||
|
var filename = filepath.Base(path)
|
||||||
homeDir, homeErr := os.UserHomeDir()
|
homeDir, homeErr := os.UserHomeDir()
|
||||||
if homeErr == nil {
|
if homeErr == nil {
|
||||||
dir := homeDir + "/." + teaconst.ProcessName
|
dir := homeDir + "/." + teaconst.ProcessName
|
||||||
stat, err := os.Stat(dir)
|
stat, err := os.Stat(dir)
|
||||||
if err == nil && stat.IsDir() {
|
if err == nil && stat.IsDir() {
|
||||||
_ = ioutil.WriteFile(dir+"/"+filename, data, 0666)
|
err = os.WriteFile(dir+"/"+filename, data, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
} else if err != nil && os.IsNotExist(err) {
|
} else if err != nil && os.IsNotExist(err) {
|
||||||
err = os.Mkdir(dir, 0777)
|
err = os.Mkdir(dir, 0777)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_ = ioutil.WriteFile(dir+"/"+filename, data, 0666)
|
err = os.WriteFile(dir+"/"+filename, data, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 写入 /etc/edge-admin
|
// 写入 /etc/edge-admin
|
||||||
{
|
{
|
||||||
dir := "/etc/" + teaconst.ProcessName
|
var dir = "/etc/" + teaconst.ProcessName
|
||||||
stat, err := os.Stat(dir)
|
stat, err := os.Stat(dir)
|
||||||
if err == nil && stat.IsDir() {
|
if err == nil && stat.IsDir() {
|
||||||
_ = ioutil.WriteFile(dir+"/"+filename, data, 0666)
|
_ = os.WriteFile(dir+"/"+filename, data, 0666)
|
||||||
} else if err != nil && os.IsNotExist(err) {
|
} else if err != nil && os.IsNotExist(err) {
|
||||||
err = os.Mkdir(dir, 0777)
|
err = os.Mkdir(dir, 0777)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_ = ioutil.WriteFile(dir+"/"+filename, data, 0666)
|
_ = os.WriteFile(dir+"/"+filename, data, 0666)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ioutil.WriteFile(path, data, 0666)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,13 +14,7 @@ func TestLoadAPIConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIConfig_WriteFile(t *testing.T) {
|
func TestAPIConfig_WriteFile(t *testing.T) {
|
||||||
config := &APIConfig{
|
config := &APIConfig{}
|
||||||
RPC: struct {
|
|
||||||
Endpoints []string `yaml:"endpoints"`
|
|
||||||
}{},
|
|
||||||
NodeId: "1",
|
|
||||||
Secret: "2",
|
|
||||||
}
|
|
||||||
err := config.WriteFile("/tmp/api_config.yaml")
|
err := config.WriteFile("/tmp/api_config.yaml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ package configs
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"io/ioutil"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
var plusConfigFile = "plus.cache.json"
|
var plusConfigFile = "plus.cache.json"
|
||||||
@@ -17,7 +17,7 @@ type PlusConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ReadPlusConfig() *PlusConfig {
|
func ReadPlusConfig() *PlusConfig {
|
||||||
data, err := ioutil.ReadFile(Tea.ConfigFile(plusConfigFile))
|
data, err := os.ReadFile(Tea.ConfigFile(plusConfigFile))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &PlusConfig{IsPlus: false}
|
return &PlusConfig{IsPlus: false}
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ func WritePlusConfig(config *PlusConfig) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(Tea.ConfigFile(plusConfigFile), configJSON, 0777)
|
err = os.WriteFile(Tea.ConfigFile(plusConfigFile), configJSON, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
// +build !plus
|
//go:build !plus
|
||||||
|
|
||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = "0.4.10"
|
Version = "0.5.3"
|
||||||
|
|
||||||
APINodeVersion = "0.4.10"
|
APINodeVersion = "0.5.3"
|
||||||
|
|
||||||
ProductName = "Edge Admin"
|
ProductName = "Edge Admin"
|
||||||
ProcessName = "edge-admin"
|
ProcessName = "edge-admin"
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 生成Token
|
// Generate 生成Token
|
||||||
func Generate() string {
|
func Generate() string {
|
||||||
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
|
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ func Generate() string {
|
|||||||
return token
|
return token
|
||||||
}
|
}
|
||||||
|
|
||||||
// 校验Token
|
// Validate 校验Token
|
||||||
func Validate(token string) (b bool) {
|
func Validate(token string) (b bool) {
|
||||||
if len(token) == 0 {
|
if len(token) == 0 {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package nodes
|
package nodes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/errors"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
"github.com/iwind/TeaGo"
|
"github.com/iwind/TeaGo"
|
||||||
@@ -16,7 +16,6 @@ import (
|
|||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
"github.com/iwind/gosock/pkg/gosock"
|
"github.com/iwind/gosock/pkg/gosock"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@@ -91,7 +90,7 @@ func (this *AdminNode) Run() {
|
|||||||
EndAll().
|
EndAll().
|
||||||
Session(sessions.NewFileSessionManager(86400, secret), teaconst.CookieSID).
|
Session(sessions.NewFileSessionManager(86400, secret), teaconst.CookieSID).
|
||||||
ReadHeaderTimeout(3 * time.Second).
|
ReadHeaderTimeout(3 * time.Second).
|
||||||
ReadTimeout(600 * time.Second).
|
ReadTimeout(1200 * time.Second).
|
||||||
Start()
|
Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,9 +172,9 @@ func (this *AdminNode) checkServer() error {
|
|||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
// 创建文件
|
// 创建文件
|
||||||
templateFile := Tea.ConfigFile("server.template.yaml")
|
templateFile := Tea.ConfigFile("server.template.yaml")
|
||||||
data, err := ioutil.ReadFile(templateFile)
|
data, err := os.ReadFile(templateFile)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = ioutil.WriteFile(configFile, data, 0666)
|
err = os.WriteFile(configFile, data, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("create config file failed: " + err.Error())
|
return errors.New("create config file failed: " + err.Error())
|
||||||
}
|
}
|
||||||
@@ -195,7 +194,7 @@ https:
|
|||||||
cert: ""
|
cert: ""
|
||||||
key: ""
|
key: ""
|
||||||
`
|
`
|
||||||
err = ioutil.WriteFile(configFile, []byte(templateYAML), 0666)
|
err = os.WriteFile(configFile, []byte(templateYAML), 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("create config file failed: " + err.Error())
|
return errors.New("create config file failed: " + err.Error())
|
||||||
}
|
}
|
||||||
@@ -210,7 +209,7 @@ https:
|
|||||||
// 添加端口到防火墙
|
// 添加端口到防火墙
|
||||||
func (this *AdminNode) addPortsToFirewall() {
|
func (this *AdminNode) addPortsToFirewall() {
|
||||||
var configFile = Tea.ConfigFile("server.yaml")
|
var configFile = Tea.ConfigFile("server.yaml")
|
||||||
data, err := ioutil.ReadFile(configFile)
|
data, err := os.ReadFile(configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -263,9 +262,9 @@ func (this *AdminNode) startAPINode() {
|
|||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
_, err = os.Stat(path)
|
_, err = os.Stat(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
data, err := ioutil.ReadFile(path)
|
data, err := os.ReadFile(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = ioutil.WriteFile(configPath, data, 0666)
|
err = os.WriteFile(configPath, data, 0666)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
logs.Println("[NODE]recover 'edge-api/configs/api.yaml' from '" + path + "'")
|
logs.Println("[NODE]recover 'edge-api/configs/api.yaml' from '" + path + "'")
|
||||||
canStart = true
|
canStart = true
|
||||||
@@ -289,9 +288,9 @@ func (this *AdminNode) startAPINode() {
|
|||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
_, err = os.Stat(path)
|
_, err = os.Stat(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
data, err := ioutil.ReadFile(path)
|
data, err := os.ReadFile(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = ioutil.WriteFile(dbPath, data, 0666)
|
err = os.WriteFile(dbPath, data, 0666)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
logs.Println("[NODE]recover 'edge-api/configs/db.yaml' from '" + path + "'")
|
logs.Println("[NODE]recover 'edge-api/configs/db.yaml' from '" + path + "'")
|
||||||
break
|
break
|
||||||
@@ -316,12 +315,12 @@ func (this *AdminNode) startAPINode() {
|
|||||||
// 生成Secret
|
// 生成Secret
|
||||||
func (this *AdminNode) genSecret() string {
|
func (this *AdminNode) genSecret() string {
|
||||||
tmpFile := os.TempDir() + "/edge-admin-secret.tmp"
|
tmpFile := os.TempDir() + "/edge-admin-secret.tmp"
|
||||||
data, err := ioutil.ReadFile(tmpFile)
|
data, err := os.ReadFile(tmpFile)
|
||||||
if err == nil && len(data) == 32 {
|
if err == nil && len(data) == 32 {
|
||||||
return string(data)
|
return string(data)
|
||||||
}
|
}
|
||||||
secret := rands.String(32)
|
secret := rands.String(32)
|
||||||
_ = ioutil.WriteFile(tmpFile, []byte(secret), 0666)
|
_ = os.WriteFile(tmpFile, []byte(secret), 0666)
|
||||||
return secret
|
return secret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"github.com/iwind/TeaGo/rands"
|
"github.com/iwind/TeaGo/rands"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@@ -19,7 +20,9 @@ import (
|
|||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
"google.golang.org/grpc/encoding/gzip"
|
"google.golang.org/grpc/encoding/gzip"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -38,7 +41,7 @@ func NewRPCClient(apiConfig *configs.APIConfig, isPrimary bool) (*RPCClient, err
|
|||||||
return nil, errors.New("api config should not be nil")
|
return nil, errors.New("api config should not be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &RPCClient{
|
var client = &RPCClient{
|
||||||
apiConfig: apiConfig,
|
apiConfig: apiConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +126,10 @@ func (this *RPCClient) ServerRPC() pb.ServerServiceClient {
|
|||||||
return pb.NewServerServiceClient(this.pickConn())
|
return pb.NewServerServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) ServerBandwidthStatRPC() pb.ServerBandwidthStatServiceClient {
|
||||||
|
return pb.NewServerBandwidthStatServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) ServerClientSystemMonthlyStatRPC() pb.ServerClientSystemMonthlyStatServiceClient {
|
func (this *RPCClient) ServerClientSystemMonthlyStatRPC() pb.ServerClientSystemMonthlyStatServiceClient {
|
||||||
return pb.NewServerClientSystemMonthlyStatServiceClient(this.pickConn())
|
return pb.NewServerClientSystemMonthlyStatServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
@@ -316,22 +323,18 @@ func (this *RPCClient) IPLibraryRPC() pb.IPLibraryServiceClient {
|
|||||||
return pb.NewIPLibraryServiceClient(this.pickConn())
|
return pb.NewIPLibraryServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) IPLibraryFileRPC() pb.IPLibraryFileServiceClient {
|
||||||
|
return pb.NewIPLibraryFileServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) IPLibraryArtifactRPC() pb.IPLibraryArtifactServiceClient {
|
||||||
|
return pb.NewIPLibraryArtifactServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) IPListRPC() pb.IPListServiceClient {
|
func (this *RPCClient) IPListRPC() pb.IPListServiceClient {
|
||||||
return pb.NewIPListServiceClient(this.pickConn())
|
return pb.NewIPListServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *RPCClient) ReportNodeRPC() pb.ReportNodeServiceClient {
|
|
||||||
return pb.NewReportNodeServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) ReportNodeGroupRPC() pb.ReportNodeGroupServiceClient {
|
|
||||||
return pb.NewReportNodeGroupServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) ReportResultRPC() pb.ReportResultServiceClient {
|
|
||||||
return pb.NewReportResultServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) IPItemRPC() pb.IPItemServiceClient {
|
func (this *RPCClient) IPItemRPC() pb.IPItemServiceClient {
|
||||||
return pb.NewIPItemServiceClient(this.pickConn())
|
return pb.NewIPItemServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
@@ -356,6 +359,10 @@ func (this *RPCClient) RegionCityRPC() pb.RegionCityServiceClient {
|
|||||||
return pb.NewRegionCityServiceClient(this.pickConn())
|
return pb.NewRegionCityServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) RegionTownRPC() pb.RegionTownServiceClient {
|
||||||
|
return pb.NewRegionTownServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) RegionProviderRPC() pb.RegionProviderServiceClient {
|
func (this *RPCClient) RegionProviderRPC() pb.RegionProviderServiceClient {
|
||||||
return pb.NewRegionProviderServiceClient(this.pickConn())
|
return pb.NewRegionProviderServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
@@ -448,42 +455,6 @@ func (this *RPCClient) LatestItemRPC() pb.LatestItemServiceClient {
|
|||||||
return pb.NewLatestItemServiceClient(this.pickConn())
|
return pb.NewLatestItemServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *RPCClient) NSClusterRPC() pb.NSClusterServiceClient {
|
|
||||||
return pb.NewNSClusterServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) NSNodeRPC() pb.NSNodeServiceClient {
|
|
||||||
return pb.NewNSNodeServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) NSDomainRPC() pb.NSDomainServiceClient {
|
|
||||||
return pb.NewNSDomainServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) NSRecordRPC() pb.NSRecordServiceClient {
|
|
||||||
return pb.NewNSRecordServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) NSKeyRPC() pb.NSKeyServiceClient {
|
|
||||||
return pb.NewNSKeyServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) NSRouteRPC() pb.NSRouteServiceClient {
|
|
||||||
return pb.NewNSRouteServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) NSAccessLogRPC() pb.NSAccessLogServiceClient {
|
|
||||||
return pb.NewNSAccessLogServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) NSRPC() pb.NSServiceClient {
|
|
||||||
return pb.NewNSServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) NSQuestionOptionRPC() pb.NSQuestionOptionServiceClient {
|
|
||||||
return pb.NewNSQuestionOptionServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) MetricItemRPC() pb.MetricItemServiceClient {
|
func (this *RPCClient) MetricItemRPC() pb.MetricItemServiceClient {
|
||||||
return pb.NewMetricItemServiceClient(this.pickConn())
|
return pb.NewMetricItemServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
@@ -526,8 +497,8 @@ func (this *RPCClient) TrafficDailyStatRPC() pb.TrafficDailyStatServiceClient {
|
|||||||
|
|
||||||
// Context 构造Admin上下文
|
// Context 构造Admin上下文
|
||||||
func (this *RPCClient) Context(adminId int64) context.Context {
|
func (this *RPCClient) Context(adminId int64) context.Context {
|
||||||
ctx := context.Background()
|
var ctx = context.Background()
|
||||||
m := maps.Map{
|
var m = maps.Map{
|
||||||
"timestamp": time.Now().Unix(),
|
"timestamp": time.Now().Unix(),
|
||||||
"type": "admin",
|
"type": "admin",
|
||||||
"userId": adminId,
|
"userId": adminId,
|
||||||
@@ -542,15 +513,15 @@ func (this *RPCClient) Context(adminId int64) context.Context {
|
|||||||
utils.PrintError(err)
|
utils.PrintError(err)
|
||||||
return context.Background()
|
return context.Background()
|
||||||
}
|
}
|
||||||
token := base64.StdEncoding.EncodeToString(data)
|
var token = base64.StdEncoding.EncodeToString(data)
|
||||||
ctx = metadata.AppendToOutgoingContext(ctx, "nodeId", this.apiConfig.NodeId, "token", token)
|
ctx = metadata.AppendToOutgoingContext(ctx, "nodeId", this.apiConfig.NodeId, "token", token)
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
// APIContext 构造API上下文
|
// APIContext 构造API上下文
|
||||||
func (this *RPCClient) APIContext(apiNodeId int64) context.Context {
|
func (this *RPCClient) APIContext(apiNodeId int64) context.Context {
|
||||||
ctx := context.Background()
|
var ctx = context.Background()
|
||||||
m := maps.Map{
|
var m = maps.Map{
|
||||||
"timestamp": time.Now().Unix(),
|
"timestamp": time.Now().Unix(),
|
||||||
"type": "api",
|
"type": "api",
|
||||||
"userId": apiNodeId,
|
"userId": apiNodeId,
|
||||||
@@ -565,7 +536,7 @@ func (this *RPCClient) APIContext(apiNodeId int64) context.Context {
|
|||||||
utils.PrintError(err)
|
utils.PrintError(err)
|
||||||
return context.Background()
|
return context.Background()
|
||||||
}
|
}
|
||||||
token := base64.StdEncoding.EncodeToString(data)
|
var token = base64.StdEncoding.EncodeToString(data)
|
||||||
ctx = metadata.AppendToOutgoingContext(ctx, "nodeId", this.apiConfig.NodeId, "token", token)
|
ctx = metadata.AppendToOutgoingContext(ctx, "nodeId", this.apiConfig.NodeId, "token", token)
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
@@ -582,20 +553,39 @@ func (this *RPCClient) UpdateConfig(config *configs.APIConfig) error {
|
|||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
func (this *RPCClient) init() error {
|
func (this *RPCClient) init() error {
|
||||||
|
// 当前的IP地址
|
||||||
|
var localIPAddrs = this.localIPAddrs()
|
||||||
|
|
||||||
// 重新连接
|
// 重新连接
|
||||||
conns := []*grpc.ClientConn{}
|
var conns = []*grpc.ClientConn{}
|
||||||
for _, endpoint := range this.apiConfig.RPC.Endpoints {
|
for _, endpoint := range this.apiConfig.RPC.Endpoints {
|
||||||
u, err := url.Parse(endpoint)
|
u, err := url.Parse(endpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("parse endpoint failed: " + err.Error())
|
return errors.New("parse endpoint failed: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var apiHost = u.Host
|
||||||
|
|
||||||
|
// 如果本机,则将地址修改为回路地址
|
||||||
|
if lists.ContainsString(localIPAddrs, u.Hostname()) {
|
||||||
|
if strings.Contains(apiHost, "[") { // IPv6 [host]:port
|
||||||
|
apiHost = "[::1]"
|
||||||
|
} else {
|
||||||
|
apiHost = "127.0.0.1"
|
||||||
|
}
|
||||||
|
var port = u.Port()
|
||||||
|
if len(port) > 0 {
|
||||||
|
apiHost += ":" + port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var conn *grpc.ClientConn
|
var conn *grpc.ClientConn
|
||||||
var callOptions = grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(128*1024*1024),
|
var callOptions = grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(128*1024*1024),
|
||||||
grpc.UseCompressor(gzip.Name))
|
grpc.UseCompressor(gzip.Name))
|
||||||
if u.Scheme == "http" {
|
if u.Scheme == "http" {
|
||||||
conn, err = grpc.Dial(u.Host, grpc.WithTransportCredentials(insecure.NewCredentials()), callOptions)
|
conn, err = grpc.Dial(apiHost, grpc.WithTransportCredentials(insecure.NewCredentials()), callOptions)
|
||||||
} else if u.Scheme == "https" {
|
} else if u.Scheme == "https" {
|
||||||
conn, err = grpc.Dial(u.Host, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
|
conn, err = grpc.Dial(apiHost, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
})), callOptions)
|
})), callOptions)
|
||||||
} else {
|
} else {
|
||||||
@@ -622,7 +612,7 @@ func (this *RPCClient) pickConn() *grpc.ClientConn {
|
|||||||
|
|
||||||
// 检查连接状态
|
// 检查连接状态
|
||||||
if len(this.conns) > 0 {
|
if len(this.conns) > 0 {
|
||||||
availableConns := []*grpc.ClientConn{}
|
var availableConns = []*grpc.ClientConn{}
|
||||||
for _, state := range []connectivity.State{connectivity.Ready, connectivity.Idle, connectivity.Connecting} {
|
for _, state := range []connectivity.State{connectivity.Ready, connectivity.Idle, connectivity.Connecting} {
|
||||||
for _, conn := range this.conns {
|
for _, conn := range this.conns {
|
||||||
if conn.GetState() == state {
|
if conn.GetState() == state {
|
||||||
@@ -674,3 +664,18 @@ func (this *RPCClient) Close() error {
|
|||||||
|
|
||||||
return lastErr
|
return lastErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) localIPAddrs() []string {
|
||||||
|
localInterfaceAddrs, err := net.InterfaceAddrs()
|
||||||
|
var localIPAddrs = []string{}
|
||||||
|
if err == nil {
|
||||||
|
for _, addr := range localInterfaceAddrs {
|
||||||
|
var addrString = addr.String()
|
||||||
|
var index = strings.Index(addrString, "/")
|
||||||
|
if index > 0 {
|
||||||
|
localIPAddrs = append(localIPAddrs, addrString[:index])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return localIPAddrs
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ func TestRPCClient_NodeRPC(t *testing.T) {
|
|||||||
func TestRPC_Dial_HTTP(t *testing.T) {
|
func TestRPC_Dial_HTTP(t *testing.T) {
|
||||||
client, err := NewRPCClient(&configs.APIConfig{
|
client, err := NewRPCClient(&configs.APIConfig{
|
||||||
RPC: struct {
|
RPC: struct {
|
||||||
Endpoints []string `yaml:"endpoints"`
|
Endpoints []string `yaml:"endpoints"`
|
||||||
|
DisableUpdate bool `yaml:"disableUpdate"`
|
||||||
}{
|
}{
|
||||||
Endpoints: []string{"http://127.0.0.1:8004"},
|
Endpoints: []string{"http://127.0.0.1:8004"},
|
||||||
},
|
},
|
||||||
@@ -56,7 +57,8 @@ func TestRPC_Dial_HTTP(t *testing.T) {
|
|||||||
func TestRPC_Dial_HTTP_2(t *testing.T) {
|
func TestRPC_Dial_HTTP_2(t *testing.T) {
|
||||||
client, err := NewRPCClient(&configs.APIConfig{
|
client, err := NewRPCClient(&configs.APIConfig{
|
||||||
RPC: struct {
|
RPC: struct {
|
||||||
Endpoints []string `yaml:"endpoints"`
|
Endpoints []string `yaml:"endpoints"`
|
||||||
|
DisableUpdate bool `yaml:"disableUpdate"`
|
||||||
}{
|
}{
|
||||||
Endpoints: []string{"https://127.0.0.1:8003"},
|
Endpoints: []string{"https://127.0.0.1:8003"},
|
||||||
},
|
},
|
||||||
@@ -77,7 +79,8 @@ func TestRPC_Dial_HTTP_2(t *testing.T) {
|
|||||||
func TestRPC_Dial_HTTPS(t *testing.T) {
|
func TestRPC_Dial_HTTPS(t *testing.T) {
|
||||||
client, err := NewRPCClient(&configs.APIConfig{
|
client, err := NewRPCClient(&configs.APIConfig{
|
||||||
RPC: struct {
|
RPC: struct {
|
||||||
Endpoints []string `yaml:"endpoints"`
|
Endpoints []string `yaml:"endpoints"`
|
||||||
|
DisableUpdate bool `yaml:"disableUpdate"`
|
||||||
}{
|
}{
|
||||||
Endpoints: []string{"https://127.0.0.1:8004"},
|
Endpoints: []string{"https://127.0.0.1:8004"},
|
||||||
},
|
},
|
||||||
@@ -94,3 +97,53 @@ func TestRPC_Dial_HTTPS(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Log(resp.Node)
|
t.Log(resp.Node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkNewRPCClient(b *testing.B) {
|
||||||
|
config, err := configs.LoadAPIConfig()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
rpc, err := NewRPCClient(config, true)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
resp, err := rpc.AdminRPC().LoginAdmin(rpc.Context(0), &pb.LoginAdminRequest{
|
||||||
|
Username: "admin",
|
||||||
|
Password: stringutil.Md5("123456"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
_ = resp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkNewRPCClient_2(b *testing.B) {
|
||||||
|
config, err := configs.LoadAPIConfig()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
rpc, err := NewRPCClient(config, true)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var conn = rpc.AdminRPC()
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
resp, err := conn.LoginAdmin(rpc.Context(0), &pb.LoginAdminRequest{
|
||||||
|
Username: "admin",
|
||||||
|
Password: stringutil.Md5("123456"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
_ = resp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
stringutil "github.com/iwind/TeaGo/utils/string"
|
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -95,7 +95,7 @@ func (this *CheckUpdatesTask) Loop() error {
|
|||||||
defer func() {
|
defer func() {
|
||||||
_ = resp.Body.Close()
|
_ = resp.Body.Close()
|
||||||
}()
|
}()
|
||||||
data, err := ioutil.ReadAll(resp.Body)
|
data, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("read api failed: " + err.Error())
|
return errors.New("read api failed: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -143,8 +144,9 @@ func (this *SyncAPINodesTask) testEndpoints(endpoints []string) bool {
|
|||||||
cancel()
|
cancel()
|
||||||
}()
|
}()
|
||||||
var conn *grpc.ClientConn
|
var conn *grpc.ClientConn
|
||||||
|
|
||||||
if u.Scheme == "http" {
|
if u.Scheme == "http" {
|
||||||
conn, err = grpc.DialContext(ctx, u.Host, grpc.WithInsecure(), grpc.WithBlock())
|
conn, err = grpc.DialContext(ctx, u.Host, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock())
|
||||||
} else if u.Scheme == "https" {
|
} else if u.Scheme == "https" {
|
||||||
conn, err = grpc.DialContext(ctx, u.Host, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
|
conn, err = grpc.DialContext(ctx, u.Host, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
|
|||||||
12
internal/utils/email.go
Normal file
12
internal/utils/email.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import "regexp"
|
||||||
|
|
||||||
|
var emailReg = regexp.MustCompile(`(?i)^[a-z\d]+([._+-]*[a-z\d]+)*@([a-z\d]+[a-z\d-]*[a-z\d]+\.)+[a-z\d]+$`)
|
||||||
|
|
||||||
|
// ValidateEmail 校验电子邮箱格式
|
||||||
|
func ValidateEmail(email string) bool {
|
||||||
|
return emailReg.MatchString(email)
|
||||||
|
}
|
||||||
22
internal/utils/email_test.go
Normal file
22
internal/utils/email_test.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package utils_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||||
|
"github.com/iwind/TeaGo/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValidateEmail(t *testing.T) {
|
||||||
|
var a = assert.NewAssertion(t)
|
||||||
|
a.IsTrue(utils.ValidateEmail("aaaa@gmail.com"))
|
||||||
|
a.IsTrue(utils.ValidateEmail("a.b@gmail.com"))
|
||||||
|
a.IsTrue(utils.ValidateEmail("a.b.c.d@gmail.com"))
|
||||||
|
a.IsTrue(utils.ValidateEmail("aaaa@gmail.com.cn"))
|
||||||
|
a.IsTrue(utils.ValidateEmail("hello.world.123@gmail.123.com"))
|
||||||
|
a.IsTrue(utils.ValidateEmail("10000@qq.com"))
|
||||||
|
a.IsFalse(utils.ValidateEmail("aaaa.@gmail.com"))
|
||||||
|
a.IsFalse(utils.ValidateEmail("aaaa@gmail"))
|
||||||
|
a.IsFalse(utils.ValidateEmail("aaaa@123"))
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package nodelogutils
|
package nodelogutils
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// +build linux
|
//go:build linux
|
||||||
|
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/files"
|
"github.com/iwind/TeaGo/files"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -16,7 +15,7 @@ import (
|
|||||||
var systemdServiceFile = "/etc/systemd/system/edge-admin.service"
|
var systemdServiceFile = "/etc/systemd/system/edge-admin.service"
|
||||||
var initServiceFile = "/etc/init.d/" + teaconst.SystemdServiceName
|
var initServiceFile = "/etc/init.d/" + teaconst.SystemdServiceName
|
||||||
|
|
||||||
// 安装服务
|
// Install 安装服务
|
||||||
func (this *ServiceManager) Install(exePath string, args []string) error {
|
func (this *ServiceManager) Install(exePath string, args []string) error {
|
||||||
if os.Getgid() != 0 {
|
if os.Getgid() != 0 {
|
||||||
return errors.New("only root users can install the service")
|
return errors.New("only root users can install the service")
|
||||||
@@ -30,7 +29,7 @@ func (this *ServiceManager) Install(exePath string, args []string) error {
|
|||||||
return this.installSystemdService(systemd, exePath, args)
|
return this.installSystemdService(systemd, exePath, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 启动服务
|
// Start 启动服务
|
||||||
func (this *ServiceManager) Start() error {
|
func (this *ServiceManager) Start() error {
|
||||||
if os.Getgid() != 0 {
|
if os.Getgid() != 0 {
|
||||||
return errors.New("only root users can start the service")
|
return errors.New("only root users can start the service")
|
||||||
@@ -47,7 +46,7 @@ func (this *ServiceManager) Start() error {
|
|||||||
return exec.Command("service", teaconst.ProcessName, "start").Start()
|
return exec.Command("service", teaconst.ProcessName, "start").Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除服务
|
// Uninstall 删除服务
|
||||||
func (this *ServiceManager) Uninstall() error {
|
func (this *ServiceManager) Uninstall() error {
|
||||||
if os.Getgid() != 0 {
|
if os.Getgid() != 0 {
|
||||||
return errors.New("only root users can uninstall the service")
|
return errors.New("only root users can uninstall the service")
|
||||||
@@ -83,13 +82,13 @@ func (this *ServiceManager) installInitService(exePath string, args []string) er
|
|||||||
return errors.New("'scripts/" + shortName + "' file not exists")
|
return errors.New("'scripts/" + shortName + "' file not exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := ioutil.ReadFile(scriptFile)
|
data, err := os.ReadFile(scriptFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
data = regexp.MustCompile("INSTALL_DIR=.+").ReplaceAll(data, []byte("INSTALL_DIR="+Tea.Root))
|
data = regexp.MustCompile("INSTALL_DIR=.+").ReplaceAll(data, []byte("INSTALL_DIR="+Tea.Root))
|
||||||
err = ioutil.WriteFile(initServiceFile, data, 0777)
|
err = os.WriteFile(initServiceFile, data, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -137,7 +136,7 @@ ExecReload=` + exePath + ` reload
|
|||||||
WantedBy=multi-user.target`
|
WantedBy=multi-user.target`
|
||||||
|
|
||||||
// write file
|
// write file
|
||||||
err := ioutil.WriteFile(systemdServiceFile, []byte(desc), 0777)
|
err := os.WriteFile(systemdServiceFile, []byte(desc), 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// +build !linux,!windows
|
//go:build !linux && !windows
|
||||||
|
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// +build windows
|
//go:build windows
|
||||||
|
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// format address
|
// FormatAddress format address
|
||||||
func FormatAddress(addr string) string {
|
func FormatAddress(addr string) string {
|
||||||
if strings.HasSuffix(addr, "unix:") {
|
if strings.HasSuffix(addr, "unix:") {
|
||||||
return addr
|
return addr
|
||||||
@@ -17,7 +17,7 @@ func FormatAddress(addr string) string {
|
|||||||
return addr
|
return addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分割数字
|
// SplitNumbers 分割数字
|
||||||
func SplitNumbers(numbers string) (result []int64) {
|
func SplitNumbers(numbers string) (result []int64) {
|
||||||
if len(numbers) == 0 {
|
if len(numbers) == 0 {
|
||||||
return
|
return
|
||||||
|
|||||||
67
internal/utils/strings_stream.go
Normal file
67
internal/utils/strings_stream.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FilterNotEmpty(item string) bool {
|
||||||
|
return len(item) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func MapAddPrefixFunc(prefix string) func(item string) string {
|
||||||
|
return func(item string) string {
|
||||||
|
if !strings.HasPrefix(item, prefix) {
|
||||||
|
return prefix + item
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type StringsStream struct {
|
||||||
|
s []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStringsStream(s []string) *StringsStream {
|
||||||
|
return &StringsStream{s: s}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *StringsStream) Map(f ...func(item string) string) *StringsStream {
|
||||||
|
for index, item := range this.s {
|
||||||
|
for _, f1 := range f {
|
||||||
|
item = f1(item)
|
||||||
|
}
|
||||||
|
this.s[index] = item
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *StringsStream) Filter(f ...func(item string) bool) *StringsStream {
|
||||||
|
for _, f1 := range f {
|
||||||
|
var newStrings = []string{}
|
||||||
|
for _, item := range this.s {
|
||||||
|
if f1(item) {
|
||||||
|
newStrings = append(newStrings, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.s = newStrings
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *StringsStream) Unique() *StringsStream {
|
||||||
|
var newStrings = []string{}
|
||||||
|
for _, item := range this.s {
|
||||||
|
if !lists.ContainsString(newStrings, item) {
|
||||||
|
newStrings = append(newStrings, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.s = newStrings
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *StringsStream) Result() []string {
|
||||||
|
return this.s
|
||||||
|
}
|
||||||
25
internal/utils/strings_stream_test.go
Normal file
25
internal/utils/strings_stream_test.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package utils_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStringsStream_Filter(t *testing.T) {
|
||||||
|
var stream = utils.NewStringsStream([]string{"a", "b", "1", "2", "", "png", "a"})
|
||||||
|
stream.Filter(func(item string) bool {
|
||||||
|
return len(item) > 0
|
||||||
|
})
|
||||||
|
t.Log(stream.Result())
|
||||||
|
stream.Map(func(item string) string {
|
||||||
|
return "." + item
|
||||||
|
})
|
||||||
|
t.Log(stream.Result())
|
||||||
|
stream.Unique()
|
||||||
|
t.Log(stream.Result())
|
||||||
|
stream.Map(strings.ToUpper, strings.ToLower)
|
||||||
|
t.Log(stream.Result())
|
||||||
|
}
|
||||||
292
internal/utils/upgrade_manager.go
Normal file
292
internal/utils/upgrade_manager.go
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpgradeFileWriter struct {
|
||||||
|
rawWriter io.Writer
|
||||||
|
written int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUpgradeFileWriter(rawWriter io.Writer) *UpgradeFileWriter {
|
||||||
|
return &UpgradeFileWriter{rawWriter: rawWriter}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpgradeFileWriter) Write(p []byte) (n int, err error) {
|
||||||
|
n, err = this.rawWriter.Write(p)
|
||||||
|
this.written += int64(n)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpgradeFileWriter) TotalWritten() int64 {
|
||||||
|
return this.written
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpgradeManager struct {
|
||||||
|
client *http.Client
|
||||||
|
|
||||||
|
component string
|
||||||
|
|
||||||
|
newVersion string
|
||||||
|
contentLength int64
|
||||||
|
isDownloading bool
|
||||||
|
writer *UpgradeFileWriter
|
||||||
|
body io.ReadCloser
|
||||||
|
isCancelled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUpgradeManager(component string) *UpgradeManager {
|
||||||
|
return &UpgradeManager{
|
||||||
|
component: component,
|
||||||
|
client: &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CheckRedirect: nil,
|
||||||
|
Jar: nil,
|
||||||
|
Timeout: 30 * time.Minute,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpgradeManager) Start() error {
|
||||||
|
if this.isDownloading {
|
||||||
|
return errors.New("another process is running")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isDownloading = true
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
this.client.CloseIdleConnections()
|
||||||
|
this.isDownloading = false
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 检查unzip
|
||||||
|
unzipExe, _ := exec.LookPath("unzip")
|
||||||
|
if len(unzipExe) == 0 {
|
||||||
|
// TODO install unzip automatically or pack with a static 'unzip' file
|
||||||
|
return errors.New("can not find 'unzip' command")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查cp
|
||||||
|
cpExe, _ := exec.LookPath("cp")
|
||||||
|
if len(cpExe) == 0 {
|
||||||
|
return errors.New("can not find 'cp' command")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查新版本
|
||||||
|
var downloadURL = ""
|
||||||
|
{
|
||||||
|
var url = teaconst.UpdatesURL
|
||||||
|
var osName = runtime.GOOS
|
||||||
|
if Tea.IsTesting() && osName == "darwin" {
|
||||||
|
osName = "linux"
|
||||||
|
}
|
||||||
|
url = strings.ReplaceAll(url, "${os}", osName)
|
||||||
|
url = strings.ReplaceAll(url, "${arch}", runtime.GOARCH)
|
||||||
|
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("create url request failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := this.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("read latest version failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = resp.Body.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return errors.New("read latest version failed: invalid response code '" + types.String(resp.StatusCode) + "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("read latest version failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var m = maps.Map{}
|
||||||
|
err = json.Unmarshal(data, &m)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("invalid response data: " + err.Error() + ", origin data: " + string(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
var code = m.GetInt("code")
|
||||||
|
if code != 200 {
|
||||||
|
return errors.New(m.GetString("message"))
|
||||||
|
}
|
||||||
|
|
||||||
|
var dataMap = m.GetMap("data")
|
||||||
|
var downloadHost = dataMap.GetString("host")
|
||||||
|
var versions = dataMap.GetSlice("versions")
|
||||||
|
var downloadPath = ""
|
||||||
|
for _, component := range versions {
|
||||||
|
var componentMap = maps.NewMap(component)
|
||||||
|
if componentMap.Has("version") {
|
||||||
|
if componentMap.GetString("code") == this.component {
|
||||||
|
var version = componentMap.GetString("version")
|
||||||
|
if stringutil.VersionCompare(version, teaconst.Version) > 0 {
|
||||||
|
this.newVersion = version
|
||||||
|
downloadPath = componentMap.GetString("url")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(downloadPath) == 0 {
|
||||||
|
return errors.New("no latest version to download")
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadURL = downloadHost + downloadPath
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
req, err := http.NewRequest(http.MethodGet, downloadURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("create download request failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := this.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("download failed: " + downloadURL + ": " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = resp.Body.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return errors.New("download failed: " + downloadURL + ": invalid response code '" + types.String(resp.StatusCode) + "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.contentLength = resp.ContentLength
|
||||||
|
this.body = resp.Body
|
||||||
|
|
||||||
|
// download to tmp
|
||||||
|
var tmpDir = os.TempDir()
|
||||||
|
var filename = filepath.Base(downloadURL)
|
||||||
|
|
||||||
|
var destFile = tmpDir + "/" + filename
|
||||||
|
_ = os.Remove(destFile)
|
||||||
|
|
||||||
|
fp, err := os.Create(destFile)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("create file failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
// 删除安装文件
|
||||||
|
_ = os.Remove(destFile)
|
||||||
|
}()
|
||||||
|
|
||||||
|
this.writer = NewUpgradeFileWriter(fp)
|
||||||
|
|
||||||
|
_, err = io.Copy(this.writer, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
_ = fp.Close()
|
||||||
|
if this.isCancelled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("download failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = fp.Close()
|
||||||
|
|
||||||
|
// unzip
|
||||||
|
var unzipDir = tmpDir + "/edge-" + this.component + "-tmp"
|
||||||
|
stat, err := os.Stat(unzipDir)
|
||||||
|
if err == nil && stat.IsDir() {
|
||||||
|
err = os.RemoveAll(unzipDir)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("remove old dir '" + unzipDir + "' failed: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var unzipCmd = exec.Command(unzipExe, "-q", "-o", destFile, "-d", unzipDir)
|
||||||
|
var unzipStderr = &bytes.Buffer{}
|
||||||
|
unzipCmd.Stderr = unzipStderr
|
||||||
|
err = unzipCmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("unzip installation file failed: " + err.Error() + ": " + unzipStderr.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
installationFiles, err := filepath.Glob(unzipDir + "/edge-" + this.component + "/*")
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("lookup installation files failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// cp to target dir
|
||||||
|
currentExe, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("reveal current executable file path failed: " + err.Error())
|
||||||
|
}
|
||||||
|
var targetDir = filepath.Dir(filepath.Dir(currentExe))
|
||||||
|
if !Tea.IsTesting() {
|
||||||
|
for _, installationFile := range installationFiles {
|
||||||
|
var cpCmd = exec.Command(cpExe, "-R", "-f", installationFile, targetDir)
|
||||||
|
var cpStderr = &bytes.Buffer{}
|
||||||
|
cpCmd.Stderr = cpStderr
|
||||||
|
err = cpCmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("overwrite installation files failed: '" + cpCmd.String() + "': " + cpStderr.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove tmp
|
||||||
|
_ = os.RemoveAll(unzipDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpgradeManager) IsDownloading() bool {
|
||||||
|
return this.isDownloading
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpgradeManager) Progress() float32 {
|
||||||
|
if this.contentLength <= 0 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if this.writer == nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return float32(this.writer.TotalWritten()) / float32(this.contentLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpgradeManager) NewVersion() string {
|
||||||
|
return this.newVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpgradeManager) Cancel() error {
|
||||||
|
this.isCancelled = true
|
||||||
|
this.isDownloading = false
|
||||||
|
|
||||||
|
if this.body != nil {
|
||||||
|
_ = this.body.Close()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
35
internal/utils/upgrade_manager_test.go
Normal file
35
internal/utils/upgrade_manager_test.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package utils_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewUpgradeManager(t *testing.T) {
|
||||||
|
var manager = utils.NewUpgradeManager("admin")
|
||||||
|
|
||||||
|
var ticker = time.NewTicker(2 * time.Second)
|
||||||
|
go func() {
|
||||||
|
for range ticker.C {
|
||||||
|
if manager.IsDownloading() {
|
||||||
|
t.Logf("%.2f%%", manager.Progress()*100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
/**go func() {
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
if manager.IsDownloading() {
|
||||||
|
t.Log("cancel downloading")
|
||||||
|
_ = manager.Cancel()
|
||||||
|
}
|
||||||
|
}()**/
|
||||||
|
|
||||||
|
err := manager.Start()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -111,7 +111,7 @@ func (this *Page) AsHTML() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 每页数
|
// 每页数
|
||||||
result = append(result, `<select class="ui dropdown" style="height:34px;padding-top:0;padding-bottom:0;margin-left:1em;color:#666" onchange="ChangePageSize(this.value)">
|
result = append(result, `<select class="ui dropdown" style="padding-top:0;padding-bottom:0;margin-left:1em;color:#666" onchange="ChangePageSize(this.value)">
|
||||||
<option value="10">[每页]</option>`+this.renderSizeOption(10)+
|
<option value="10">[每页]</option>`+this.renderSizeOption(10)+
|
||||||
this.renderSizeOption(20)+
|
this.renderSizeOption(20)+
|
||||||
this.renderSizeOption(30)+
|
this.renderSizeOption(30)+
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"io/ioutil"
|
"github.com/iwind/gosock/pkg/gosock"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fail 提示服务器错误信息
|
// Fail 提示服务器错误信息
|
||||||
@@ -46,6 +47,25 @@ func FailPage(action actions.ActionWrapper, err error) {
|
|||||||
|
|
||||||
var isRPCConnError bool
|
var isRPCConnError bool
|
||||||
err, isRPCConnError = rpcerrors.HumanError(err, apiEndpoints, Tea.ConfigFile("api.yaml"))
|
err, isRPCConnError = rpcerrors.HumanError(err, apiEndpoints, Tea.ConfigFile("api.yaml"))
|
||||||
|
var apiNodeIsStarting = false
|
||||||
|
var apiNodeProgress = ""
|
||||||
|
if isRPCConnError {
|
||||||
|
// API节点是否正在启动
|
||||||
|
var sock = gosock.NewTmpSock("edge-api")
|
||||||
|
reply, err := sock.SendTimeout(&gosock.Command{
|
||||||
|
Code: "starting",
|
||||||
|
Params: nil,
|
||||||
|
}, 1*time.Second)
|
||||||
|
if err == nil && reply != nil {
|
||||||
|
var params = maps.NewMap(reply.Params)
|
||||||
|
if params.GetBool("isStarting") {
|
||||||
|
apiNodeIsStarting = true
|
||||||
|
|
||||||
|
var progressMap = params.GetMap("progress")
|
||||||
|
apiNodeProgress = progressMap.GetString("description")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
action.Object().ResponseWriter.WriteHeader(http.StatusInternalServerError)
|
action.Object().ResponseWriter.WriteHeader(http.StatusInternalServerError)
|
||||||
if len(action.Object().Request.Header.Get("X-Requested-With")) > 0 {
|
if len(action.Object().Request.Header.Get("X-Requested-With")) > 0 {
|
||||||
@@ -68,7 +88,7 @@ func FailPage(action actions.ActionWrapper, err error) {
|
|||||||
var issuesHTML = ""
|
var issuesHTML = ""
|
||||||
if isLocalAPI {
|
if isLocalAPI {
|
||||||
// 读取本地API节点的issues
|
// 读取本地API节点的issues
|
||||||
issuesData, issuesErr := ioutil.ReadFile(Tea.Root + "/edge-api/logs/issues.log")
|
issuesData, issuesErr := os.ReadFile(Tea.Root + "/edge-api/logs/issues.log")
|
||||||
if issuesErr == nil {
|
if issuesErr == nil {
|
||||||
var issueMaps = []maps.Map{}
|
var issueMaps = []maps.Map{}
|
||||||
issuesErr = json.Unmarshal(issuesData, &issueMaps)
|
issuesErr = json.Unmarshal(issuesData, &issueMaps)
|
||||||
@@ -91,14 +111,25 @@ func FailPage(action actions.ActionWrapper, err error) {
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div style="background: #eee; border: 1px #ccc solid; padding: 10px; font-size: 12px; line-height: 1.8">
|
<div style="background: #eee; border: 1px #ccc solid; padding: 10px; font-size: 12px; line-height: 1.8">
|
||||||
` + teaconst.ErrServer + `
|
`
|
||||||
|
if apiNodeIsStarting { // API节点正在启动
|
||||||
|
html += "<div class=\"red\">API节点正在启动,请耐心等待完成"
|
||||||
|
|
||||||
|
if len(apiNodeProgress) > 0 {
|
||||||
|
html += ":" + apiNodeProgress
|
||||||
|
}
|
||||||
|
|
||||||
|
html += "</div>"
|
||||||
|
} else {
|
||||||
|
html += teaconst.ErrServer + `
|
||||||
<div>可以通过查看 <strong><em>$安装目录/logs/run.log</em></strong> 日志文件查看具体的错误提示。</div>
|
<div>可以通过查看 <strong><em>$安装目录/logs/run.log</em></strong> 日志文件查看具体的错误提示。</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
<div class="red">Error: ` + err.Error() + `</div>`
|
<div class="red">Error: ` + err.Error() + `</div>`
|
||||||
|
|
||||||
if len(issuesHTML) > 0 {
|
if len(issuesHTML) > 0 {
|
||||||
html += ` <hr/>
|
html += ` <hr/>
|
||||||
<div class="red">` + issuesHTML + `</div>`
|
<div class="red">` + issuesHTML + `</div>`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
action.Object().WriteString(html + `
|
action.Object().WriteString(html + `
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ func (this *DeleteAction) RunPost(params struct {
|
|||||||
var apiNode = nodeResp.ApiNode
|
var apiNode = nodeResp.ApiNode
|
||||||
if apiNode == nil {
|
if apiNode == nil {
|
||||||
this.Success()
|
this.Success()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if apiNode.IsOn {
|
if apiNode.IsOn {
|
||||||
countResp, err := this.RPC().APINodeRPC().CountAllEnabledAndOnAPINodes(this.AdminContext(), &pb.CountAllEnabledAndOnAPINodesRequest{})
|
countResp, err := this.RPC().APINodeRPC().CountAllEnabledAndOnAPINodes(this.AdminContext(), &pb.CountAllEnabledAndOnAPINodesRequest{})
|
||||||
|
|||||||
@@ -5,9 +5,12 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"net"
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 添加地址
|
// CreateAddrPopupAction 添加地址
|
||||||
type CreateAddrPopupAction struct {
|
type CreateAddrPopupAction struct {
|
||||||
actionutils.ParentAction
|
actionutils.ParentAction
|
||||||
}
|
}
|
||||||
@@ -30,12 +33,31 @@ func (this *CreateAddrPopupAction) RunPost(params struct {
|
|||||||
Field("addr", params.Addr).
|
Field("addr", params.Addr).
|
||||||
Require("请输入访问地址")
|
Require("请输入访问地址")
|
||||||
|
|
||||||
|
// 兼容URL
|
||||||
|
if regexp.MustCompile(`^(?i)(http|https)://`).MatchString(params.Addr) {
|
||||||
|
u, err := url.Parse(params.Addr)
|
||||||
|
if err != nil {
|
||||||
|
this.FailField("addr", "错误的访问地址,不需要添加http://或https://")
|
||||||
|
}
|
||||||
|
params.Addr = u.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动添加端口
|
||||||
|
if !strings.Contains(params.Addr, ":") {
|
||||||
|
switch params.Protocol {
|
||||||
|
case "http":
|
||||||
|
params.Addr += ":80"
|
||||||
|
case "https":
|
||||||
|
params.Addr += ":443"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
host, port, err := net.SplitHostPort(params.Addr)
|
host, port, err := net.SplitHostPort(params.Addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.FailField("addr", "错误的访问地址")
|
this.FailField("addr", "错误的访问地址")
|
||||||
}
|
}
|
||||||
|
|
||||||
addrConfig := &serverconfigs.NetworkAddressConfig{
|
var addrConfig = &serverconfigs.NetworkAddressConfig{
|
||||||
Protocol: serverconfigs.Protocol(params.Protocol),
|
Protocol: serverconfigs.Protocol(params.Protocol),
|
||||||
Host: host,
|
Host: host,
|
||||||
PortRange: port,
|
PortRange: port,
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -46,7 +45,7 @@ func (this *InstallAction) RunGet(params struct {
|
|||||||
"isNotFound": false,
|
"isNotFound": false,
|
||||||
}
|
}
|
||||||
dbConfigFile := Tea.ConfigFile("api_db.yaml")
|
dbConfigFile := Tea.ConfigFile("api_db.yaml")
|
||||||
data, err := ioutil.ReadFile(dbConfigFile)
|
data, err := os.ReadFile(dbConfigFile)
|
||||||
dbConfigMap["config"] = string(data)
|
dbConfigMap["config"] = string(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
dbConfigMap["error"] = err.Error()
|
dbConfigMap["error"] = err.Error()
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"net"
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UpdateAddrPopupAction struct {
|
type UpdateAddrPopupAction struct {
|
||||||
@@ -27,6 +30,26 @@ func (this *UpdateAddrPopupAction) RunPost(params struct {
|
|||||||
params.Must.
|
params.Must.
|
||||||
Field("addr", params.Addr).
|
Field("addr", params.Addr).
|
||||||
Require("请输入访问地址")
|
Require("请输入访问地址")
|
||||||
|
|
||||||
|
// 兼容URL
|
||||||
|
if regexp.MustCompile(`^(?i)(http|https)://`).MatchString(params.Addr) {
|
||||||
|
u, err := url.Parse(params.Addr)
|
||||||
|
if err != nil {
|
||||||
|
this.FailField("addr", "错误的访问地址,不需要添加http://或https://")
|
||||||
|
}
|
||||||
|
params.Addr = u.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动添加端口
|
||||||
|
if !strings.Contains(params.Addr, ":") {
|
||||||
|
switch params.Protocol {
|
||||||
|
case "http":
|
||||||
|
params.Addr += ":80"
|
||||||
|
case "https":
|
||||||
|
params.Addr += ":443"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
host, port, err := net.SplitHostPort(params.Addr)
|
host, port, err := net.SplitHostPort(params.Addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.FailField("addr", "错误的访问地址")
|
this.FailField("addr", "错误的访问地址")
|
||||||
|
|||||||
@@ -5,11 +5,14 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"net"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -27,7 +30,7 @@ func (this *CreateNodeAction) Init() {
|
|||||||
func (this *CreateNodeAction) RunGet(params struct {
|
func (this *CreateNodeAction) RunGet(params struct {
|
||||||
ClusterId int64
|
ClusterId int64
|
||||||
}) {
|
}) {
|
||||||
leftMenuItems := []maps.Map{
|
var leftMenuItems = []maps.Map{
|
||||||
{
|
{
|
||||||
"name": "单个创建",
|
"name": "单个创建",
|
||||||
"url": "/clusters/cluster/createNode?clusterId=" + strconv.FormatInt(params.ClusterId, 10),
|
"url": "/clusters/cluster/createNode?clusterId=" + strconv.FormatInt(params.ClusterId, 10),
|
||||||
@@ -47,7 +50,7 @@ func (this *CreateNodeAction) RunGet(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dnsRouteMaps := []maps.Map{}
|
var dnsRouteMaps = []maps.Map{}
|
||||||
this.Data["dnsDomainId"] = 0
|
this.Data["dnsDomainId"] = 0
|
||||||
if clusterDNSResp.Domain != nil {
|
if clusterDNSResp.Domain != nil {
|
||||||
domainId := clusterDNSResp.Domain.Id
|
domainId := clusterDNSResp.Domain.Id
|
||||||
@@ -76,8 +79,8 @@ func (this *CreateNodeAction) RunGet(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
apiNodes := apiNodesResp.ApiNodes
|
var apiNodes = apiNodesResp.ApiNodes
|
||||||
apiEndpoints := []string{}
|
var apiEndpoints = []string{}
|
||||||
for _, apiNode := range apiNodes {
|
for _, apiNode := range apiNodes {
|
||||||
if !apiNode.IsOn {
|
if !apiNode.IsOn {
|
||||||
continue
|
continue
|
||||||
@@ -86,6 +89,9 @@ func (this *CreateNodeAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
|
this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
|
||||||
|
|
||||||
|
// 安装文件下载
|
||||||
|
this.Data["installerFiles"] = clusterutils.ListInstallerFiles()
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +124,7 @@ func (this *CreateNodeAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IP地址
|
// IP地址
|
||||||
ipAddresses := []maps.Map{}
|
var ipAddresses = []maps.Map{}
|
||||||
if len(params.IpAddressesJSON) > 0 {
|
if len(params.IpAddressesJSON) > 0 {
|
||||||
err := json.Unmarshal(params.IpAddressesJSON, &ipAddresses)
|
err := json.Unmarshal(params.IpAddressesJSON, &ipAddresses)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -127,10 +133,29 @@ func (this *CreateNodeAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(ipAddresses) == 0 {
|
if len(ipAddresses) == 0 {
|
||||||
this.Fail("请至少输入一个IP地址")
|
// 检查Name中是否包含IP
|
||||||
|
var ipv4Reg = regexp.MustCompile(`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`)
|
||||||
|
var ipMatches = ipv4Reg.FindStringSubmatch(params.Name)
|
||||||
|
if len(ipMatches) > 0 {
|
||||||
|
var nodeIP = ipMatches[0]
|
||||||
|
if net.ParseIP(nodeIP) != nil {
|
||||||
|
ipAddresses = []maps.Map{
|
||||||
|
{
|
||||||
|
"ip": nodeIP,
|
||||||
|
"canAccess": true,
|
||||||
|
"isOn": true,
|
||||||
|
"isUp": true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ipAddresses) == 0 {
|
||||||
|
this.Fail("请至少输入一个IP地址")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dnsRouteCodes := []string{}
|
var dnsRouteCodes = []string{}
|
||||||
if len(params.DnsRoutesJSON) > 0 {
|
if len(params.DnsRoutesJSON) > 0 {
|
||||||
err := json.Unmarshal(params.DnsRoutesJSON, &dnsRouteCodes)
|
err := json.Unmarshal(params.DnsRoutesJSON, &dnsRouteCodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -140,7 +165,7 @@ func (this *CreateNodeAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO 检查登录授权
|
// TODO 检查登录授权
|
||||||
loginInfo := &pb.NodeLogin{
|
var loginInfo = &pb.NodeLogin{
|
||||||
Id: 0,
|
Id: 0,
|
||||||
Name: "SSH",
|
Name: "SSH",
|
||||||
Type: "ssh",
|
Type: "ssh",
|
||||||
@@ -165,7 +190,7 @@ func (this *CreateNodeAction) RunPost(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
nodeId := createResp.NodeId
|
var nodeId = createResp.NodeId
|
||||||
|
|
||||||
// IP地址
|
// IP地址
|
||||||
var resultIPAddresses = []string{}
|
var resultIPAddresses = []string{}
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package cluster
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DownloadInstallerAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *DownloadInstallerAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *DownloadInstallerAction) RunGet(params struct {
|
||||||
|
Name string
|
||||||
|
}) {
|
||||||
|
if len(params.Name) == 0 {
|
||||||
|
this.ResponseWriter.WriteHeader(http.StatusNotFound)
|
||||||
|
this.WriteString("file not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查文件名
|
||||||
|
// 以防止路径穿越等风险
|
||||||
|
if !regexp.MustCompile(`^[a-zA-Z0-9.-]+$`).MatchString(params.Name) {
|
||||||
|
this.ResponseWriter.WriteHeader(http.StatusNotFound)
|
||||||
|
this.WriteString("file not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var zipFile = Tea.Root + "/edge-api/deploy/" + params.Name
|
||||||
|
fp, err := os.OpenFile(zipFile, os.O_RDWR, 0444)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
this.ResponseWriter.WriteHeader(http.StatusNotFound)
|
||||||
|
this.WriteString("file not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ResponseWriter.WriteHeader(http.StatusInternalServerError)
|
||||||
|
this.WriteString("file can not be opened")
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = fp.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
stat, err := fp.Stat()
|
||||||
|
if err != nil {
|
||||||
|
this.ResponseWriter.WriteHeader(http.StatusInternalServerError)
|
||||||
|
this.WriteString("file can not be opened")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.AddHeader("Content-Disposition", "attachment; filename=\""+params.Name+"\";")
|
||||||
|
this.AddHeader("Content-Type", "application/zip")
|
||||||
|
this.AddHeader("Content-Length", types.String(stat.Size()))
|
||||||
|
_, _ = io.Copy(this.ResponseWriter, fp)
|
||||||
|
}
|
||||||
@@ -48,7 +48,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 创建日志
|
// 创建日志
|
||||||
defer this.CreateLog(oplogs.LevelInfo, "创建节点分组", createResp.NodeGroupId)
|
defer this.CreateLog(oplogs.LevelInfo, "创建节点分组 %d", createResp.NodeGroupId)
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ func init() {
|
|||||||
GetPost("/updateNodeSSH", new(UpdateNodeSSHAction)).
|
GetPost("/updateNodeSSH", new(UpdateNodeSSHAction)).
|
||||||
GetPost("/installManual", new(InstallManualAction)).
|
GetPost("/installManual", new(InstallManualAction)).
|
||||||
Post("/suggestLoginPorts", new(SuggestLoginPortsAction)).
|
Post("/suggestLoginPorts", new(SuggestLoginPortsAction)).
|
||||||
|
Get("/downloadInstaller", new(DownloadInstallerAction)).
|
||||||
|
|
||||||
// 节点相关
|
// 节点相关
|
||||||
Prefix("/clusters/cluster/node").
|
Prefix("/clusters/cluster/node").
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ func (this *DetailAction) Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *DetailAction) RunGet(params struct {
|
func (this *DetailAction) RunGet(params struct {
|
||||||
NodeId int64
|
NodeId int64
|
||||||
|
ClusterId int64
|
||||||
}) {
|
}) {
|
||||||
this.Data["nodeId"] = params.NodeId
|
this.Data["nodeId"] = params.NodeId
|
||||||
|
|
||||||
@@ -43,13 +44,13 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
// 主集群
|
// 主集群
|
||||||
var clusterMap maps.Map = nil
|
var clusterMap maps.Map = nil
|
||||||
if node.NodeCluster != nil {
|
if node.NodeCluster != nil {
|
||||||
clusterId := node.NodeCluster.Id
|
var clusterId = node.NodeCluster.Id
|
||||||
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: clusterId})
|
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: clusterId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cluster := clusterResp.NodeCluster
|
var cluster = clusterResp.NodeCluster
|
||||||
if cluster != nil {
|
if cluster != nil {
|
||||||
clusterMap = maps.Map{
|
clusterMap = maps.Map{
|
||||||
"id": cluster.Id,
|
"id": cluster.Id,
|
||||||
@@ -69,6 +70,14 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 当前访问集群的DNS设置
|
||||||
|
clusterDNSInfo, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["dnsIsExcludingLnNode"] = clusterDNSInfo != nil && !clusterDNSInfo.IncludingLnNodes && node.Level > 1
|
||||||
|
|
||||||
// IP地址
|
// IP地址
|
||||||
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
|
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledNodeIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledNodeIPAddressesWithNodeIdRequest{
|
||||||
NodeId: params.NodeId,
|
NodeId: params.NodeId,
|
||||||
@@ -286,6 +295,11 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lnAddrs = node.LnAddrs
|
||||||
|
if lnAddrs == nil {
|
||||||
|
lnAddrs = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
this.Data["node"] = maps.Map{
|
this.Data["node"] = maps.Map{
|
||||||
"id": node.Id,
|
"id": node.Id,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
@@ -303,6 +317,7 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
"routes": routeMaps,
|
"routes": routeMaps,
|
||||||
"level": node.Level,
|
"level": node.Level,
|
||||||
"levelInfo": nodeconfigs.FindNodeLevel(int(node.Level)),
|
"levelInfo": nodeconfigs.FindNodeLevel(int(node.Level)),
|
||||||
|
"lnAddrs": lnAddrs,
|
||||||
|
|
||||||
"status": maps.Map{
|
"status": maps.Map{
|
||||||
"isActive": status.IsActive,
|
"isActive": status.IsActive,
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
package node
|
package node
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,6 +36,20 @@ func (this *InstallAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 最近运行目录
|
||||||
|
var exeRoot = ""
|
||||||
|
if len(node.StatusJSON) > 0 {
|
||||||
|
var nodeStatus = &nodeconfigs.NodeStatus{}
|
||||||
|
err = json.Unmarshal(node.StatusJSON, nodeStatus)
|
||||||
|
if err == nil {
|
||||||
|
var exePath = nodeStatus.ExePath
|
||||||
|
if len(exePath) > 0 {
|
||||||
|
exeRoot = filepath.Dir(filepath.Dir(exePath))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.Data["exeRoot"] = exeRoot
|
||||||
|
|
||||||
// 安装信息
|
// 安装信息
|
||||||
if node.InstallStatus != nil {
|
if node.InstallStatus != nil {
|
||||||
this.Data["installStatus"] = maps.Map{
|
this.Data["installStatus"] = maps.Map{
|
||||||
@@ -70,7 +88,7 @@ func (this *InstallAction) RunGet(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
apiNodes := apiNodesResp.ApiNodes
|
var apiNodes = apiNodesResp.ApiNodes
|
||||||
apiEndpoints := []string{}
|
apiEndpoints := []string{}
|
||||||
for _, apiNode := range apiNodes {
|
for _, apiNode := range apiNodes {
|
||||||
if !apiNode.IsOn {
|
if !apiNode.IsOn {
|
||||||
@@ -87,6 +105,10 @@ func (this *InstallAction) RunGet(params struct {
|
|||||||
nodeMap["secret"] = node.Secret
|
nodeMap["secret"] = node.Secret
|
||||||
nodeMap["cluster"] = clusterMap
|
nodeMap["cluster"] = clusterMap
|
||||||
|
|
||||||
|
// 安装文件
|
||||||
|
var installerFiles = clusterutils.ListInstallerFiles()
|
||||||
|
this.Data["installerFiles"] = installerFiles
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package nodeutils
|
package nodeutils
|
||||||
|
|
||||||
|
|||||||
@@ -102,8 +102,12 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
this.FailField("tcpMaxConnectionsPerIP", "TCP: 单IP TCP最大连接数不能小于"+types.String(nodeconfigs.DefaultTCPMinConnectionsPerIP))
|
this.FailField("tcpMaxConnectionsPerIP", "TCP: 单IP TCP最大连接数不能小于"+types.String(nodeconfigs.DefaultTCPMinConnectionsPerIP))
|
||||||
}
|
}
|
||||||
|
|
||||||
if tcpConfig.NewConnectionsRate > 0 && tcpConfig.NewConnectionsRate < nodeconfigs.DefaultTCPNewConnectionsMinRate {
|
if tcpConfig.NewConnectionsMinutelyRate > 0 && tcpConfig.NewConnectionsMinutelyRate < nodeconfigs.DefaultTCPNewConnectionsMinMinutelyRate {
|
||||||
this.FailField("tcpNewConnectionsRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinRate))
|
this.FailField("tcpNewConnectionsMinutelyRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinMinutelyRate))
|
||||||
|
}
|
||||||
|
|
||||||
|
if tcpConfig.NewConnectionsSecondlyRate > 0 && tcpConfig.NewConnectionsSecondlyRate < nodeconfigs.DefaultTCPNewConnectionsMinSecondlyRate {
|
||||||
|
this.FailField("tcpNewConnectionsSecondlyRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinSecondlyRate))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Port
|
// Port
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UpdateAction struct {
|
type UpdateAction struct {
|
||||||
@@ -61,7 +62,7 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ipAddressMaps := []maps.Map{}
|
var ipAddressMaps = []maps.Map{}
|
||||||
for _, addr := range ipAddressesResp.NodeIPAddresses {
|
for _, addr := range ipAddressesResp.NodeIPAddresses {
|
||||||
thresholds, err := ipaddressutils.InitNodeIPAddressThresholds(this.Parent(), addr.Id)
|
thresholds, err := ipaddressutils.InitNodeIPAddressThresholds(this.Parent(), addr.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -109,6 +110,12 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
"level": node.Level,
|
"level": node.Level,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if node.LnAddrs == nil {
|
||||||
|
nodeMap["lnAddrs"] = []string{}
|
||||||
|
} else {
|
||||||
|
nodeMap["lnAddrs"] = node.LnAddrs
|
||||||
|
}
|
||||||
|
|
||||||
if node.NodeCluster != nil {
|
if node.NodeCluster != nil {
|
||||||
nodeMap["primaryCluster"] = maps.Map{
|
nodeMap["primaryCluster"] = maps.Map{
|
||||||
"id": node.NodeCluster.Id,
|
"id": node.NodeCluster.Id,
|
||||||
@@ -149,6 +156,7 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
SecondaryClusterIds []byte
|
SecondaryClusterIds []byte
|
||||||
IsOn bool
|
IsOn bool
|
||||||
Level int32
|
Level int32
|
||||||
|
LnAddrs []string
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
}) {
|
}) {
|
||||||
@@ -178,7 +186,7 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IP地址
|
// IP地址
|
||||||
ipAddresses := []maps.Map{}
|
var ipAddresses = []maps.Map{}
|
||||||
if len(params.IPAddressesJSON) > 0 {
|
if len(params.IPAddressesJSON) > 0 {
|
||||||
err := json.Unmarshal(params.IPAddressesJSON, &ipAddresses)
|
err := json.Unmarshal(params.IPAddressesJSON, &ipAddresses)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -195,6 +203,27 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
this.Fail("没有权限修改节点级别:" + types.String(params.Level))
|
this.Fail("没有权限修改节点级别:" + types.String(params.Level))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查Ln节点地址
|
||||||
|
var lnAddrs = []string{}
|
||||||
|
if params.Level > 1 {
|
||||||
|
for _, lnAddr := range params.LnAddrs {
|
||||||
|
if len(lnAddr) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理 host:port
|
||||||
|
host, _, err := net.SplitHostPort(lnAddr)
|
||||||
|
if err == nil {
|
||||||
|
lnAddr = host
|
||||||
|
}
|
||||||
|
|
||||||
|
if net.ParseIP(lnAddr) == nil {
|
||||||
|
this.Fail("L2级别访问地址 '" + lnAddr + "' 格式错误,请纠正后再提交")
|
||||||
|
}
|
||||||
|
lnAddrs = append(lnAddrs, lnAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_, err := this.RPC().NodeRPC().UpdateNode(this.AdminContext(), &pb.UpdateNodeRequest{
|
_, err := this.RPC().NodeRPC().UpdateNode(this.AdminContext(), &pb.UpdateNodeRequest{
|
||||||
NodeId: params.NodeId,
|
NodeId: params.NodeId,
|
||||||
NodeGroupId: params.GroupId,
|
NodeGroupId: params.GroupId,
|
||||||
@@ -204,6 +233,7 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
SecondaryNodeClusterIds: secondaryClusterIds,
|
SecondaryNodeClusterIds: secondaryClusterIds,
|
||||||
IsOn: params.IsOn,
|
IsOn: params.IsOn,
|
||||||
Level: params.Level,
|
Level: params.Level,
|
||||||
|
LnAddrs: lnAddrs,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package node
|
package node
|
||||||
|
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ func (this *NodesAction) RunGet(params struct {
|
|||||||
this.Data["groups"] = groupMaps
|
this.Data["groups"] = groupMaps
|
||||||
|
|
||||||
// 所有区域
|
// 所有区域
|
||||||
regionsResp, err := this.RPC().NodeRegionRPC().FindAllEnabledAndOnNodeRegions(this.AdminContext(), &pb.FindAllEnabledAndOnNodeRegionsRequest{})
|
regionsResp, err := this.RPC().NodeRegionRPC().FindAllAvailableNodeRegions(this.AdminContext(), &pb.FindAllAvailableNodeRegionsRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -75,8 +75,12 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
this.FailField("tcpMaxConnectionsPerIP", "TCP: 单IP TCP最大连接数不能小于"+types.String(nodeconfigs.DefaultTCPMinConnectionsPerIP))
|
this.FailField("tcpMaxConnectionsPerIP", "TCP: 单IP TCP最大连接数不能小于"+types.String(nodeconfigs.DefaultTCPMinConnectionsPerIP))
|
||||||
}
|
}
|
||||||
|
|
||||||
if tcpConfig.NewConnectionsRate > 0 && tcpConfig.NewConnectionsRate < nodeconfigs.DefaultTCPNewConnectionsMinRate {
|
if tcpConfig.NewConnectionsMinutelyRate > 0 && tcpConfig.NewConnectionsMinutelyRate < nodeconfigs.DefaultTCPNewConnectionsMinMinutelyRate {
|
||||||
this.FailField("tcpNewConnectionsRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinRate))
|
this.FailField("tcpNewConnectionsMinutelyRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinMinutelyRate))
|
||||||
|
}
|
||||||
|
|
||||||
|
if tcpConfig.NewConnectionsSecondlyRate > 0 && tcpConfig.NewConnectionsSecondlyRate < nodeconfigs.DefaultTCPNewConnectionsMinSecondlyRate {
|
||||||
|
this.FailField("tcpNewConnectionsSecondlyRate", "TCP: 单IP连接速率不能小于"+types.String(nodeconfigs.DefaultTCPNewConnectionsMinSecondlyRate))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Port
|
// Port
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexAction struct {
|
type IndexAction struct {
|
||||||
@@ -41,10 +42,23 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
this.Data["dnsName"] = dnsInfoResp.Name
|
this.Data["dnsName"] = dnsInfoResp.Name
|
||||||
this.Data["nodesAutoSync"] = dnsInfoResp.NodesAutoSync
|
this.Data["nodesAutoSync"] = dnsInfoResp.NodesAutoSync
|
||||||
this.Data["serversAutoSync"] = dnsInfoResp.ServersAutoSync
|
this.Data["serversAutoSync"] = dnsInfoResp.ServersAutoSync
|
||||||
|
|
||||||
|
var domainProviderMap = maps.Map{
|
||||||
|
"id": 0,
|
||||||
|
"name": "",
|
||||||
|
}
|
||||||
if dnsInfoResp.Domain != nil {
|
if dnsInfoResp.Domain != nil {
|
||||||
this.Data["domainId"] = dnsInfoResp.Domain.Id
|
this.Data["domainId"] = dnsInfoResp.Domain.Id
|
||||||
this.Data["domainName"] = dnsInfoResp.Domain.Name
|
this.Data["domainName"] = dnsInfoResp.Domain.Name
|
||||||
|
|
||||||
|
if dnsInfoResp.Provider != nil {
|
||||||
|
domainProviderMap = maps.Map{
|
||||||
|
"id": dnsInfoResp.Provider.Id,
|
||||||
|
"name": dnsInfoResp.Provider.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
this.Data["domainProvider"] = domainProviderMap
|
||||||
|
|
||||||
if len(dnsInfoResp.CnameRecords) == 0 {
|
if len(dnsInfoResp.CnameRecords) == 0 {
|
||||||
this.Data["cnameRecords"] = []string{}
|
this.Data["cnameRecords"] = []string{}
|
||||||
@@ -53,6 +67,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
this.Data["ttl"] = dnsInfoResp.Ttl
|
this.Data["ttl"] = dnsInfoResp.Ttl
|
||||||
this.Data["cnameAsDomain"] = dnsInfoResp.CnameAsDomain
|
this.Data["cnameAsDomain"] = dnsInfoResp.CnameAsDomain
|
||||||
|
this.Data["includingLnNodes"] = dnsInfoResp.IncludingLnNodes
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
@@ -60,13 +75,14 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
func (this *IndexAction) RunPost(params struct {
|
func (this *IndexAction) RunPost(params struct {
|
||||||
ClusterId int64
|
ClusterId int64
|
||||||
|
|
||||||
DnsDomainId int64
|
DnsDomainId int64
|
||||||
DnsName string
|
DnsName string
|
||||||
NodesAutoSync bool
|
NodesAutoSync bool
|
||||||
ServersAutoSync bool
|
ServersAutoSync bool
|
||||||
CnameRecords []string
|
CnameRecords []string
|
||||||
Ttl int32
|
Ttl int32
|
||||||
CnameAsDomain bool
|
CnameAsDomain bool
|
||||||
|
IncludingLnNodes bool
|
||||||
|
|
||||||
ConfirmResetDomain bool // 是否确认重置域名
|
ConfirmResetDomain bool // 是否确认重置域名
|
||||||
|
|
||||||
@@ -107,14 +123,15 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err := this.RPC().NodeClusterRPC().UpdateNodeClusterDNS(this.AdminContext(), &pb.UpdateNodeClusterDNSRequest{
|
_, err := this.RPC().NodeClusterRPC().UpdateNodeClusterDNS(this.AdminContext(), &pb.UpdateNodeClusterDNSRequest{
|
||||||
NodeClusterId: params.ClusterId,
|
NodeClusterId: params.ClusterId,
|
||||||
DnsName: params.DnsName,
|
DnsName: params.DnsName,
|
||||||
DnsDomainId: params.DnsDomainId,
|
DnsDomainId: params.DnsDomainId,
|
||||||
NodesAutoSync: params.NodesAutoSync,
|
NodesAutoSync: params.NodesAutoSync,
|
||||||
ServersAutoSync: params.ServersAutoSync,
|
ServersAutoSync: params.ServersAutoSync,
|
||||||
CnameRecords: params.CnameRecords,
|
CnameRecords: params.CnameRecords,
|
||||||
Ttl: params.Ttl,
|
Ttl: params.Ttl,
|
||||||
CnameAsDomain: params.CnameAsDomain,
|
CnameAsDomain: params.CnameAsDomain,
|
||||||
|
IncludingLnNodes: params.IncludingLnNodes,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package globalServerConfig
|
||||||
|
|
||||||
|
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/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
this.Nav("", "setting", "")
|
||||||
|
this.SecondMenu("globalServerConfig")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
}) {
|
||||||
|
configResp, err := this.RPC().NodeClusterRPC().FindNodeClusterGlobalServerConfig(this.AdminContext(), &pb.FindNodeClusterGlobalServerConfigRequest{NodeClusterId: params.ClusterId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var configJSON = configResp.GlobalServerConfigJSON
|
||||||
|
var config = serverconfigs.DefaultGlobalServerConfig()
|
||||||
|
if len(configJSON) > 0 {
|
||||||
|
err = json.Unmarshal(configJSON, config)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.Data["config"] = config
|
||||||
|
|
||||||
|
var httpAllDomainMismatchActionContentHTML = ""
|
||||||
|
if config.HTTPAll.DomainMismatchAction != nil {
|
||||||
|
httpAllDomainMismatchActionContentHTML = config.HTTPAll.DomainMismatchAction.Options.GetString("contentHTML")
|
||||||
|
} else {
|
||||||
|
httpAllDomainMismatchActionContentHTML = `<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<title>404 not found</title>
|
||||||
|
<style>
|
||||||
|
* { font-family: Roboto, system-ui, sans-serif; }
|
||||||
|
h3, p { text-align: center; }
|
||||||
|
p { color: grey; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h3>Error: 404 Page Not Found</h3>
|
||||||
|
<h3>找不到您要访问的页面。</h3>
|
||||||
|
|
||||||
|
<p>原因:找不到当前访问域名对应的网站,请联系网站管理员。</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>`
|
||||||
|
}
|
||||||
|
this.Data["httpAllDomainMismatchActionContentHTML"] = httpAllDomainMismatchActionContentHTML
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunPost(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
|
||||||
|
HttpAllMatchDomainStrictly bool
|
||||||
|
HttpAllDomainMismatchActionContentHTML string
|
||||||
|
HttpAllAllowMismatchDomainsJSON []byte
|
||||||
|
HttpAllAllowNodeIP bool
|
||||||
|
HttpAllDefaultDomain string
|
||||||
|
|
||||||
|
LogRecordServerError bool
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("修改集群 %d 全局配置", params.ClusterId)
|
||||||
|
|
||||||
|
configResp, err := this.RPC().NodeClusterRPC().FindNodeClusterGlobalServerConfig(this.AdminContext(), &pb.FindNodeClusterGlobalServerConfigRequest{NodeClusterId: params.ClusterId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var configJSON = configResp.GlobalServerConfigJSON
|
||||||
|
var config = serverconfigs.DefaultGlobalServerConfig()
|
||||||
|
if len(configJSON) > 0 {
|
||||||
|
err = json.Unmarshal(configJSON, config)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config.HTTPAll.MatchDomainStrictly = params.HttpAllMatchDomainStrictly
|
||||||
|
config.HTTPAll.DomainMismatchAction = &serverconfigs.DomainMismatchAction{
|
||||||
|
Code: serverconfigs.DomainMismatchActionPage,
|
||||||
|
Options: maps.Map{
|
||||||
|
"statusCode": 404,
|
||||||
|
"contentHTML": params.HttpAllDomainMismatchActionContentHTML,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var allowMismatchDomains = []string{}
|
||||||
|
if len(params.HttpAllAllowMismatchDomainsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(params.HttpAllAllowMismatchDomainsJSON, &allowMismatchDomains)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config.HTTPAll.AllowMismatchDomains = allowMismatchDomains
|
||||||
|
config.HTTPAll.AllowNodeIP = params.HttpAllAllowNodeIP
|
||||||
|
config.HTTPAll.DefaultDomain = params.HttpAllDefaultDomain
|
||||||
|
|
||||||
|
config.Log.RecordServerError = params.LogRecordServerError
|
||||||
|
|
||||||
|
err = config.Init()
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("配置校验失败:" + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
configJSON, err = json.Marshal(config)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterGlobalServerConfig(this.AdminContext(), &pb.UpdateNodeClusterGlobalServerConfigRequest{
|
||||||
|
NodeClusterId: params.ClusterId,
|
||||||
|
GlobalServerConfigJSON: configJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package health
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CheckDomainAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CheckDomainAction) RunPost(params struct {
|
||||||
|
Host string
|
||||||
|
ClusterId int64
|
||||||
|
}) {
|
||||||
|
this.Data["isOk"] = true // 默认为TRUE
|
||||||
|
|
||||||
|
var host = params.Host
|
||||||
|
if len(host) > 0 &&
|
||||||
|
!strings.Contains(host, "{") /** 包含变量 **/ {
|
||||||
|
h, _, err := net.SplitHostPort(host)
|
||||||
|
if err == nil && len(h) > 0 {
|
||||||
|
host = h
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否为IP
|
||||||
|
if net.ParseIP(host) != nil {
|
||||||
|
this.Success()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
host = strings.ToLower(host)
|
||||||
|
resp, err := this.RPC().ServerRPC().CheckServerNameDuplicationInNodeCluster(this.AdminContext(), &pb.CheckServerNameDuplicationInNodeClusterRequest{
|
||||||
|
NodeClusterId: params.ClusterId,
|
||||||
|
ServerNames: []string{host},
|
||||||
|
SupportWildcard: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(resp.DuplicatedServerNames) == 0 {
|
||||||
|
this.Data["isOk"] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package settings
|
package settings
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||||
@@ -65,13 +66,29 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
this.Data["timeZoneLocation"] = nodeconfigs.FindTimeZoneLocation(cluster.TimeZone)
|
this.Data["timeZoneLocation"] = nodeconfigs.FindTimeZoneLocation(cluster.TimeZone)
|
||||||
|
|
||||||
|
// 时钟
|
||||||
|
var clockConfig = nodeconfigs.DefaultClockConfig()
|
||||||
|
if len(cluster.ClockJSON) > 0 {
|
||||||
|
err = json.Unmarshal(cluster.ClockJSON, clockConfig)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if clockConfig == nil {
|
||||||
|
clockConfig = nodeconfigs.DefaultClockConfig()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.Data["cluster"] = maps.Map{
|
this.Data["cluster"] = maps.Map{
|
||||||
"id": cluster.Id,
|
"id": cluster.Id,
|
||||||
"name": cluster.Name,
|
"name": cluster.Name,
|
||||||
"installDir": cluster.InstallDir,
|
"installDir": cluster.InstallDir,
|
||||||
"timeZone": cluster.TimeZone,
|
"timeZone": cluster.TimeZone,
|
||||||
"nodeMaxThreads": cluster.NodeMaxThreads,
|
"nodeMaxThreads": cluster.NodeMaxThreads,
|
||||||
"autoOpenPorts": cluster.AutoOpenPorts,
|
"autoOpenPorts": cluster.AutoOpenPorts,
|
||||||
|
"clock": clockConfig,
|
||||||
|
"autoRemoteStart": cluster.AutoRemoteStart,
|
||||||
|
"autoInstallNftables": cluster.AutoInstallNftables,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认值
|
// 默认值
|
||||||
@@ -84,13 +101,17 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
|
|
||||||
// RunPost 保存设置
|
// RunPost 保存设置
|
||||||
func (this *IndexAction) RunPost(params struct {
|
func (this *IndexAction) RunPost(params struct {
|
||||||
ClusterId int64
|
ClusterId int64
|
||||||
Name string
|
Name string
|
||||||
GrantId int64
|
GrantId int64
|
||||||
InstallDir string
|
InstallDir string
|
||||||
TimeZone string
|
TimeZone string
|
||||||
NodeMaxThreads int32
|
NodeMaxThreads int32
|
||||||
AutoOpenPorts bool
|
AutoOpenPorts bool
|
||||||
|
ClockAutoSync bool
|
||||||
|
ClockServer string
|
||||||
|
AutoRemoteStart bool
|
||||||
|
AutoInstallNftables bool
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
}) {
|
}) {
|
||||||
@@ -108,14 +129,32 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
Lte(int64(nodeconfigs.DefaultMaxThreadsMax), "单节点最大线程数最大值不能大于"+types.String(nodeconfigs.DefaultMaxThreadsMax))
|
Lte(int64(nodeconfigs.DefaultMaxThreadsMax), "单节点最大线程数最大值不能大于"+types.String(nodeconfigs.DefaultMaxThreadsMax))
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := this.RPC().NodeClusterRPC().UpdateNodeCluster(this.AdminContext(), &pb.UpdateNodeClusterRequest{
|
var clockConfig = nodeconfigs.DefaultClockConfig()
|
||||||
NodeClusterId: params.ClusterId,
|
clockConfig.AutoSync = params.ClockAutoSync
|
||||||
Name: params.Name,
|
clockConfig.Server = params.ClockServer
|
||||||
NodeGrantId: params.GrantId,
|
clockConfigJSON, err := json.Marshal(clockConfig)
|
||||||
InstallDir: params.InstallDir,
|
if err != nil {
|
||||||
TimeZone: params.TimeZone,
|
this.ErrorPage(err)
|
||||||
NodeMaxThreads: params.NodeMaxThreads,
|
return
|
||||||
AutoOpenPorts: params.AutoOpenPorts,
|
}
|
||||||
|
|
||||||
|
err = clockConfig.Init()
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = this.RPC().NodeClusterRPC().UpdateNodeCluster(this.AdminContext(), &pb.UpdateNodeClusterRequest{
|
||||||
|
NodeClusterId: params.ClusterId,
|
||||||
|
Name: params.Name,
|
||||||
|
NodeGrantId: params.GrantId,
|
||||||
|
InstallDir: params.InstallDir,
|
||||||
|
TimeZone: params.TimeZone,
|
||||||
|
NodeMaxThreads: params.NodeMaxThreads,
|
||||||
|
AutoOpenPorts: params.AutoOpenPorts,
|
||||||
|
ClockJSON: clockConfigJSON,
|
||||||
|
AutoRemoteStart: params.AutoRemoteStart,
|
||||||
|
AutoInstallNftables: params.AutoInstallNftables,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
ddosProtection "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/ddos-protection"
|
ddosProtection "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/ddos-protection"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/dns"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/dns"
|
||||||
firewallActions "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/firewall-actions"
|
firewallActions "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/firewall-actions"
|
||||||
|
globalServerConfig "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/global-server-config"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/health"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/health"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/metrics"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/metrics"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/services"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/services"
|
||||||
@@ -28,6 +29,7 @@ func init() {
|
|||||||
// 健康检查
|
// 健康检查
|
||||||
GetPost("/health", new(health.IndexAction)).
|
GetPost("/health", new(health.IndexAction)).
|
||||||
GetPost("/health/runPopup", new(health.RunPopupAction)).
|
GetPost("/health/runPopup", new(health.RunPopupAction)).
|
||||||
|
Post("/health/checkDomain", new(health.CheckDomainAction)).
|
||||||
|
|
||||||
// 缓存
|
// 缓存
|
||||||
GetPost("/cache", new(cache.IndexAction)).
|
GetPost("/cache", new(cache.IndexAction)).
|
||||||
@@ -71,6 +73,10 @@ func init() {
|
|||||||
GetPost("", new(ddosProtection.IndexAction)).
|
GetPost("", new(ddosProtection.IndexAction)).
|
||||||
GetPost("/status", new(ddosProtection.StatusAction)).
|
GetPost("/status", new(ddosProtection.StatusAction)).
|
||||||
|
|
||||||
|
// 全局服务配置
|
||||||
|
Prefix("/clusters/cluster/settings/global-server-config").
|
||||||
|
GetPost("", new(globalServerConfig.IndexAction)).
|
||||||
|
|
||||||
//
|
//
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -153,6 +153,12 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, info *pb.F
|
|||||||
"isOn": info != nil && info.HasDDoSProtection,
|
"isOn": info != nil && info.HasDDoSProtection,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
items = append(items, maps.Map{
|
||||||
|
"name": "服务设置",
|
||||||
|
"url": "/clusters/cluster/settings/global-server-config?clusterId=" + clusterId,
|
||||||
|
"isActive": selectedItem == "globalServerConfig",
|
||||||
|
})
|
||||||
|
|
||||||
items = append(items, maps.Map{
|
items = append(items, maps.Map{
|
||||||
"name": "-",
|
"name": "-",
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package clusterutils
|
package clusterutils
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package clusterutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type installerFile struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
OS string `json:"os"`
|
||||||
|
Arch string `json:"arch"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListInstallerFiles() []*installerFile {
|
||||||
|
var dir = Tea.Root + "/edge-api/deploy"
|
||||||
|
matches, err := filepath.Glob(dir + "/edge-node-*.zip")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = []*installerFile{}
|
||||||
|
var reg = regexp.MustCompile(`^edge-node-(\w+)-(\w+)-v([\w.]+)\.zip$`)
|
||||||
|
for _, match := range matches {
|
||||||
|
var baseName = filepath.Base(match)
|
||||||
|
var subMatches = reg.FindStringSubmatch(baseName)
|
||||||
|
if len(subMatches) >= 4 {
|
||||||
|
var osName = subMatches[1]
|
||||||
|
if len(osName) > 0 {
|
||||||
|
osName = strings.ToUpper(osName[:1]) + osName[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
var arch = subMatches[2]
|
||||||
|
if arch == "amd64" {
|
||||||
|
arch = "x86_64"
|
||||||
|
}
|
||||||
|
|
||||||
|
var version = subMatches[3]
|
||||||
|
if version != teaconst.Version { // 只能下载当前版本
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, &installerFile{
|
||||||
|
Name: subMatches[0],
|
||||||
|
OS: osName,
|
||||||
|
Arch: arch,
|
||||||
|
Version: version,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 排序,将x86_64排在最上面
|
||||||
|
if len(result) > 0 {
|
||||||
|
sort.Slice(result, func(i, j int) bool {
|
||||||
|
return result[i].Arch == "x86_64"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -55,14 +56,19 @@ func (this *CreateAction) RunPost(params struct {
|
|||||||
// WAF策略
|
// WAF策略
|
||||||
HttpFirewallPolicyId int64
|
HttpFirewallPolicyId int64
|
||||||
|
|
||||||
|
// 服务配置
|
||||||
|
MatchDomainStrictly bool
|
||||||
|
|
||||||
// SSH相关
|
// SSH相关
|
||||||
GrantId int64
|
GrantId int64
|
||||||
InstallDir string
|
InstallDir string
|
||||||
SystemdServiceIsOn bool
|
SystemdServiceIsOn bool
|
||||||
|
AutoInstallNftables bool
|
||||||
|
|
||||||
// DNS相关
|
// DNS相关
|
||||||
DnsDomainId int64
|
DnsDomainId int64
|
||||||
DnsName string
|
DnsName string
|
||||||
|
DnsTTL int32
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
}) {
|
}) {
|
||||||
@@ -92,8 +98,17 @@ func (this *CreateAction) RunPost(params struct {
|
|||||||
|
|
||||||
// TODO 检查DnsDomainId的有效性
|
// TODO 检查DnsDomainId的有效性
|
||||||
|
|
||||||
|
// 全局服务配置
|
||||||
|
var globalServerConfig = serverconfigs.DefaultGlobalServerConfig()
|
||||||
|
globalServerConfig.HTTPAll.MatchDomainStrictly = params.MatchDomainStrictly
|
||||||
|
globalServerConfigJSON, err := json.Marshal(globalServerConfig)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 系统服务
|
// 系统服务
|
||||||
systemServices := map[string]interface{}{}
|
var systemServices = map[string]any{}
|
||||||
if params.SystemdServiceIsOn {
|
if params.SystemdServiceIsOn {
|
||||||
systemServices[nodeconfigs.SystemServiceTypeSystemd] = &nodeconfigs.SystemdServiceConfig{
|
systemServices[nodeconfigs.SystemServiceTypeSystemd] = &nodeconfigs.SystemdServiceConfig{
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
@@ -106,14 +121,17 @@ func (this *CreateAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createResp, err := this.RPC().NodeClusterRPC().CreateNodeCluster(this.AdminContext(), &pb.CreateNodeClusterRequest{
|
createResp, err := this.RPC().NodeClusterRPC().CreateNodeCluster(this.AdminContext(), &pb.CreateNodeClusterRequest{
|
||||||
Name: params.Name,
|
Name: params.Name,
|
||||||
NodeGrantId: params.GrantId,
|
NodeGrantId: params.GrantId,
|
||||||
InstallDir: params.InstallDir,
|
InstallDir: params.InstallDir,
|
||||||
DnsDomainId: params.DnsDomainId,
|
DnsDomainId: params.DnsDomainId,
|
||||||
DnsName: params.DnsName,
|
DnsName: params.DnsName,
|
||||||
HttpCachePolicyId: params.CachePolicyId,
|
DnsTTL: params.DnsTTL,
|
||||||
HttpFirewallPolicyId: params.HttpFirewallPolicyId,
|
HttpCachePolicyId: params.CachePolicyId,
|
||||||
SystemServicesJSON: systemServicesJSON,
|
HttpFirewallPolicyId: params.HttpFirewallPolicyId,
|
||||||
|
SystemServicesJSON: systemServicesJSON,
|
||||||
|
GlobalServerConfigJSON: globalServerConfigJSON,
|
||||||
|
AutoInstallNftables: params.AutoInstallNftables,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package logs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -29,5 +30,8 @@ func (this *FixAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通知左侧数字Badge更新
|
||||||
|
helpers.NotifyNodeLogsCountChange()
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package logs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,5 +22,8 @@ func (this *FixAllAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通知左侧数字Badge更新
|
||||||
|
helpers.NotifyNodeLogsCountChange()
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,8 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var firstUnreadNodeMap maps.Map = nil
|
||||||
|
|
||||||
var logs = []maps.Map{}
|
var logs = []maps.Map{}
|
||||||
for _, log := range logsResp.NodeLogs {
|
for _, log := range logsResp.NodeLogs {
|
||||||
// 节点信息
|
// 节点信息
|
||||||
@@ -132,6 +134,13 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if params.Type == "unread" && firstUnreadNodeMap == nil {
|
||||||
|
firstUnreadNodeMap = maps.Map{
|
||||||
|
"id": node.Id,
|
||||||
|
"name": node.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 服务信息
|
// 服务信息
|
||||||
var serverMap = maps.Map{"id": 0}
|
var serverMap = maps.Map{"id": 0}
|
||||||
if log.ServerId > 0 {
|
if log.ServerId > 0 {
|
||||||
@@ -174,5 +183,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
this.Data["logs"] = logs
|
this.Data["logs"] = logs
|
||||||
|
|
||||||
|
this.Data["firstUnreadNode"] = firstUnreadNodeMap
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package logs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,5 +21,8 @@ func (this *ReadAllLogsAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通知左侧数字Badge更新
|
||||||
|
helpers.NotifyNodeLogsCountChange()
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ package logs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,14 +15,21 @@ type ReadLogsAction struct {
|
|||||||
|
|
||||||
func (this *ReadLogsAction) RunPost(params struct {
|
func (this *ReadLogsAction) RunPost(params struct {
|
||||||
LogIds []int64
|
LogIds []int64
|
||||||
|
|
||||||
|
NodeId int64
|
||||||
}) {
|
}) {
|
||||||
_, err := this.RPC().NodeLogRPC().UpdateNodeLogsRead(this.AdminContext(), &pb.UpdateNodeLogsReadRequest{
|
_, err := this.RPC().NodeLogRPC().UpdateNodeLogsRead(this.AdminContext(), &pb.UpdateNodeLogsReadRequest{
|
||||||
NodeLogIds: params.LogIds,
|
NodeLogIds: params.LogIds,
|
||||||
|
NodeId: params.NodeId,
|
||||||
|
Role: nodeconfigs.NodeRoleNode,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通知左侧数字Badge更新
|
||||||
|
helpers.NotifyNodeLogsCountChange()
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ func (this *NodesAction) RunGet(params struct {
|
|||||||
this.Data["groups"] = groupMaps
|
this.Data["groups"] = groupMaps
|
||||||
|
|
||||||
// 所有区域
|
// 所有区域
|
||||||
regionsResp, err := this.RPC().NodeRegionRPC().FindAllEnabledAndOnNodeRegions(this.AdminContext(), &pb.FindAllEnabledAndOnNodeRegionsRequest{})
|
regionsResp, err := this.RPC().NodeRegionRPC().FindAllAvailableNodeRegions(this.AdminContext(), &pb.FindAllAvailableNodeRegionsRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
|||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
CSRF *actionutils.CSRF
|
||||||
}) {
|
}) {
|
||||||
defer this.CreateLogInfo("修改流量价格项目", params.ItemId)
|
defer this.CreateLogInfo("修改流量价格项目 %d", params.ItemId)
|
||||||
|
|
||||||
params.Must.
|
params.Must.
|
||||||
Field("name", params.Name).
|
Field("name", params.Name).
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func (this *PricesAction) Init() {
|
|||||||
|
|
||||||
func (this *PricesAction) RunGet(params struct{}) {
|
func (this *PricesAction) RunGet(params struct{}) {
|
||||||
// 所有价格项目
|
// 所有价格项目
|
||||||
itemsResp, err := this.RPC().NodePriceItemRPC().FindAllEnabledAndOnNodePriceItems(this.AdminContext(), &pb.FindAllEnabledAndOnNodePriceItemsRequest{Type: regionutils.PriceTypeTraffic})
|
itemsResp, err := this.RPC().NodePriceItemRPC().FindAllAvailableNodePriceItems(this.AdminContext(), &pb.FindAllAvailableNodePriceItemsRequest{Type: regionutils.PriceTypeTraffic})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func (this *SelectPopupAction) Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *SelectPopupAction) RunGet(params struct{}) {
|
func (this *SelectPopupAction) RunGet(params struct{}) {
|
||||||
regionsResp, err := this.RPC().NodeRegionRPC().FindAllEnabledAndOnNodeRegions(this.AdminContext(), &pb.FindAllEnabledAndOnNodeRegionsRequest{})
|
regionsResp, err := this.RPC().NodeRegionRPC().FindAllAvailableNodeRegions(this.AdminContext(), &pb.FindAllAvailableNodeRegionsRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dashboard/dashboardutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dashboard/dashboardutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
@@ -25,6 +26,10 @@ func (this *IndexAction) Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *IndexAction) RunGet(params struct{}) {
|
func (this *IndexAction) RunGet(params struct{}) {
|
||||||
|
// 通知菜单数字Badge更新
|
||||||
|
helpers.NotifyIPItemsCountChanges()
|
||||||
|
helpers.NotifyNodeLogsCountChange()
|
||||||
|
|
||||||
if teaconst.IsPlus {
|
if teaconst.IsPlus {
|
||||||
this.RedirectURL("/dashboard/boards")
|
this.RedirectURL("/dashboard/boards")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ func (this *RestartLocalAPINodeAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 停止1秒等待命令运行完毕
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
// 检查是否已启动
|
// 检查是否已启动
|
||||||
var countTries = 120
|
var countTries = 120
|
||||||
for {
|
for {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ type DomainOptionsAction struct {
|
|||||||
func (this *DomainOptionsAction) RunPost(params struct {
|
func (this *DomainOptionsAction) RunPost(params struct {
|
||||||
ProviderId int64
|
ProviderId int64
|
||||||
}) {
|
}) {
|
||||||
domainsResp, err := this.RPC().DNSDomainRPC().FindAllEnabledBasicDNSDomainsWithDNSProviderId(this.AdminContext(), &pb.FindAllEnabledBasicDNSDomainsWithDNSProviderIdRequest{
|
domainsResp, err := this.RPC().DNSDomainRPC().FindAllBasicDNSDomainsWithDNSProviderId(this.AdminContext(), &pb.FindAllBasicDNSDomainsWithDNSProviderIdRequest{
|
||||||
DnsProviderId: params.ProviderId,
|
DnsProviderId: params.ProviderId,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func (this *ClustersPopupAction) RunGet(params struct {
|
|||||||
DomainId int64
|
DomainId int64
|
||||||
}) {
|
}) {
|
||||||
// 域名信息
|
// 域名信息
|
||||||
domainResp, err := this.RPC().DNSDomainRPC().FindEnabledBasicDNSDomain(this.AdminContext(), &pb.FindEnabledBasicDNSDomainRequest{
|
domainResp, err := this.RPC().DNSDomainRPC().FindBasicDNSDomain(this.AdminContext(), &pb.FindBasicDNSDomainRequest{
|
||||||
DnsDomainId: params.DomainId,
|
DnsDomainId: params.DomainId,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ func ValidateDomainFormat(domain string) bool {
|
|||||||
if piece == "-" ||
|
if piece == "-" ||
|
||||||
strings.HasPrefix(piece, "-") ||
|
strings.HasPrefix(piece, "-") ||
|
||||||
strings.HasSuffix(piece, "-") ||
|
strings.HasSuffix(piece, "-") ||
|
||||||
//strings.Contains(piece, "--") ||
|
|
||||||
len(piece) > 63 ||
|
len(piece) > 63 ||
|
||||||
!regexp.MustCompile(`^[a-z0-9-]+$`).MatchString(piece) {
|
// 我们允许中文、大写字母、下划线,防止有些特殊场景下需要
|
||||||
|
!regexp.MustCompile(`^[\p{Han}_a-zA-Z0-9-]+$`).MatchString(piece) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,8 @@ func ValidateRecordName(name string) bool {
|
|||||||
strings.HasSuffix(piece, "-") ||
|
strings.HasSuffix(piece, "-") ||
|
||||||
//strings.Contains(piece, "--") ||
|
//strings.Contains(piece, "--") ||
|
||||||
len(piece) > 63 ||
|
len(piece) > 63 ||
|
||||||
!regexp.MustCompile(`^[_a-z0-9-]+$`).MatchString(piece) {
|
// 我们允许中文、大写字母、下划线,防止有些特殊场景下需要
|
||||||
|
!regexp.MustCompile(`^[\p{Han}_a-zA-Z0-9-]+$`).MatchString(piece) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ func (this *NodesPopupAction) RunGet(params struct {
|
|||||||
DomainId int64
|
DomainId int64
|
||||||
}) {
|
}) {
|
||||||
// 域名信息
|
// 域名信息
|
||||||
domainResp, err := this.RPC().DNSDomainRPC().FindEnabledBasicDNSDomain(this.AdminContext(), &pb.FindEnabledBasicDNSDomainRequest{
|
domainResp, err := this.RPC().DNSDomainRPC().FindBasicDNSDomain(this.AdminContext(), &pb.FindBasicDNSDomainRequest{
|
||||||
DnsDomainId: params.DomainId,
|
DnsDomainId: params.DomainId,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ func (this *SelectPopupAction) RunGet(params struct {
|
|||||||
|
|
||||||
// 域名信息
|
// 域名信息
|
||||||
if params.DomainId > 0 {
|
if params.DomainId > 0 {
|
||||||
domainResp, err := this.RPC().DNSDomainRPC().FindEnabledDNSDomain(this.AdminContext(), &pb.FindEnabledDNSDomainRequest{DnsDomainId: params.DomainId})
|
domainResp, err := this.RPC().DNSDomainRPC().FindDNSDomain(this.AdminContext(), &pb.FindDNSDomainRequest{DnsDomainId: params.DomainId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
domain := domainResp.DnsDomain
|
var domain = domainResp.DnsDomain
|
||||||
if domain != nil {
|
if domain != nil {
|
||||||
this.Data["domainId"] = domain.Id
|
this.Data["domainId"] = domain.Id
|
||||||
this.Data["domainName"] = domain.Name
|
this.Data["domainName"] = domain.Name
|
||||||
@@ -53,7 +53,7 @@ func (this *SelectPopupAction) RunGet(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
providerTypeMaps := []maps.Map{}
|
var providerTypeMaps = []maps.Map{}
|
||||||
for _, providerType := range providerTypesResp.ProviderTypes {
|
for _, providerType := range providerTypesResp.ProviderTypes {
|
||||||
providerTypeMaps = append(providerTypeMaps, maps.Map{
|
providerTypeMaps = append(providerTypeMaps, maps.Map{
|
||||||
"name": providerType.Name,
|
"name": providerType.Name,
|
||||||
@@ -73,15 +73,29 @@ func (this *SelectPopupAction) RunPost(params struct {
|
|||||||
}) {
|
}) {
|
||||||
this.Data["domainId"] = params.DomainId
|
this.Data["domainId"] = params.DomainId
|
||||||
this.Data["domainName"] = ""
|
this.Data["domainName"] = ""
|
||||||
|
this.Data["providerName"] = ""
|
||||||
|
|
||||||
if params.DomainId > 0 {
|
if params.DomainId > 0 {
|
||||||
domainResp, err := this.RPC().DNSDomainRPC().FindEnabledDNSDomain(this.AdminContext(), &pb.FindEnabledDNSDomainRequest{DnsDomainId: params.DomainId})
|
domainResp, err := this.RPC().DNSDomainRPC().FindDNSDomain(this.AdminContext(), &pb.FindDNSDomainRequest{DnsDomainId: params.DomainId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if domainResp.DnsDomain != nil {
|
if domainResp.DnsDomain != nil {
|
||||||
this.Data["domainName"] = domainResp.DnsDomain.Name
|
this.Data["domainName"] = domainResp.DnsDomain.Name
|
||||||
|
|
||||||
|
// 服务商名称
|
||||||
|
var providerId = domainResp.DnsDomain.ProviderId
|
||||||
|
if providerId > 0 {
|
||||||
|
providerResp, err := this.RPC().DNSProviderRPC().FindEnabledDNSProvider(this.AdminContext(), &pb.FindEnabledDNSProviderRequest{DnsProviderId: providerId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if providerResp.DnsProvider != nil {
|
||||||
|
this.Data["providerName"] = providerResp.DnsProvider.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.Data["domainId"] = 0
|
this.Data["domainId"] = 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func (this *ServersPopupAction) RunGet(params struct {
|
|||||||
DomainId int64
|
DomainId int64
|
||||||
}) {
|
}) {
|
||||||
// 域名信息
|
// 域名信息
|
||||||
domainResp, err := this.RPC().DNSDomainRPC().FindEnabledBasicDNSDomain(this.AdminContext(), &pb.FindEnabledBasicDNSDomainRequest{
|
domainResp, err := this.RPC().DNSDomainRPC().FindBasicDNSDomain(this.AdminContext(), &pb.FindBasicDNSDomainRequest{
|
||||||
DnsDomainId: params.DomainId,
|
DnsDomainId: params.DomainId,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func (this *UpdatePopupAction) Init() {
|
|||||||
func (this *UpdatePopupAction) RunGet(params struct {
|
func (this *UpdatePopupAction) RunGet(params struct {
|
||||||
DomainId int64
|
DomainId int64
|
||||||
}) {
|
}) {
|
||||||
domainResp, err := this.RPC().DNSDomainRPC().FindEnabledDNSDomain(this.AdminContext(), &pb.FindEnabledDNSDomainRequest{DnsDomainId: params.DomainId})
|
domainResp, err := this.RPC().DNSDomainRPC().FindDNSDomain(this.AdminContext(), &pb.FindDNSDomainRequest{DnsDomainId: params.DomainId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
providerTypeName := ""
|
providerTypeName := ""
|
||||||
|
|
||||||
if cluster.DnsDomainId > 0 {
|
if cluster.DnsDomainId > 0 {
|
||||||
domainResp, err := this.RPC().DNSDomainRPC().FindEnabledBasicDNSDomain(this.AdminContext(), &pb.FindEnabledBasicDNSDomainRequest{DnsDomainId: domainId})
|
domainResp, err := this.RPC().DNSDomainRPC().FindBasicDNSDomain(this.AdminContext(), &pb.FindBasicDNSDomainRequest{DnsDomainId: domainId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package providers
|
package providers
|
||||||
|
|
||||||
@@ -43,19 +42,7 @@ func (this *CreatePopupAction) RunGet(params struct{}) {
|
|||||||
this.Data["paramCustomHTTPSecret"] = rands.HexString(32)
|
this.Data["paramCustomHTTPSecret"] = rands.HexString(32)
|
||||||
|
|
||||||
// EdgeDNS集群列表
|
// EdgeDNS集群列表
|
||||||
nsClustersResp, err := this.RPC().NSClusterRPC().FindAllEnabledNSClusters(this.AdminContext(), &pb.FindAllEnabledNSClustersRequest{})
|
this.Data["nsClusters"] = []maps.Map{}
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
nsClusterMaps := []maps.Map{}
|
|
||||||
for _, nsCluster := range nsClustersResp.NsClusters {
|
|
||||||
nsClusterMaps = append(nsClusterMaps, maps.Map{
|
|
||||||
"id": nsCluster.Id,
|
|
||||||
"name": nsCluster.Name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.Data["nsClusters"] = nsClusterMaps
|
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
@@ -82,13 +69,16 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
ParamCloudFlareAPIKey string
|
ParamCloudFlareAPIKey string
|
||||||
ParamCloudFlareEmail string
|
ParamCloudFlareEmail string
|
||||||
|
|
||||||
// Local EdgeDNS
|
|
||||||
ParamLocalEdgeDNSClusterId int64
|
|
||||||
|
|
||||||
// CustomHTTP
|
// CustomHTTP
|
||||||
ParamCustomHTTPURL string
|
ParamCustomHTTPURL string
|
||||||
ParamCustomHTTPSecret string
|
ParamCustomHTTPSecret string
|
||||||
|
|
||||||
|
// EdgeDNS API
|
||||||
|
ParamEdgeDNSAPIRole string
|
||||||
|
ParamEdgeDNSAPIHost string
|
||||||
|
ParamEdgeDNSAPIAccessKeyId string
|
||||||
|
ParamEdgeDNSAPIAccessKeySecret string
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
CSRF *actionutils.CSRF
|
||||||
}) {
|
}) {
|
||||||
@@ -137,11 +127,20 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
Email("请输入正确格式的邮箱地址")
|
Email("请输入正确格式的邮箱地址")
|
||||||
apiParams["apiKey"] = params.ParamCloudFlareAPIKey
|
apiParams["apiKey"] = params.ParamCloudFlareAPIKey
|
||||||
apiParams["email"] = params.ParamCloudFlareEmail
|
apiParams["email"] = params.ParamCloudFlareEmail
|
||||||
case "localEdgeDNS":
|
case "edgeDNSAPI":
|
||||||
params.Must.
|
params.Must.
|
||||||
Field("ParamLocalEdgeDNSClusterId", params.ParamLocalEdgeDNSClusterId).
|
Field("paramEdgeDNSAPIHost", params.ParamEdgeDNSAPIHost).
|
||||||
Gt(0, "请选择域名服务集群")
|
Require("请输入API地址").
|
||||||
apiParams["clusterId"] = params.ParamLocalEdgeDNSClusterId
|
Field("paramEdgeDNSAPIRole", params.ParamEdgeDNSAPIRole).
|
||||||
|
Require("请选择AccessKey类型").
|
||||||
|
Field("paramEdgeDNSAPIAccessKeyId", params.ParamEdgeDNSAPIAccessKeyId).
|
||||||
|
Require("请输入AccessKey ID").
|
||||||
|
Field("paramEdgeDNSAPIAccessKeySecret", params.ParamEdgeDNSAPIAccessKeySecret).
|
||||||
|
Require("请输入AccessKey密钥")
|
||||||
|
apiParams["host"] = params.ParamEdgeDNSAPIHost
|
||||||
|
apiParams["role"] = params.ParamEdgeDNSAPIRole
|
||||||
|
apiParams["accessKeyId"] = params.ParamEdgeDNSAPIAccessKeyId
|
||||||
|
apiParams["accessKeySecret"] = params.ParamEdgeDNSAPIAccessKeySecret
|
||||||
case "customHTTP":
|
case "customHTTP":
|
||||||
params.Must.
|
params.Must.
|
||||||
Field("paramCustomHTTPURL", params.ParamCustomHTTPURL).
|
Field("paramCustomHTTPURL", params.ParamCustomHTTPURL).
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 域名
|
// 域名
|
||||||
countDomainsResp, err := this.RPC().DNSDomainRPC().CountAllEnabledDNSDomainsWithDNSProviderId(this.AdminContext(), &pb.CountAllEnabledDNSDomainsWithDNSProviderIdRequest{
|
countDomainsResp, err := this.RPC().DNSDomainRPC().CountAllDNSDomainsWithDNSProviderId(this.AdminContext(), &pb.CountAllDNSDomainsWithDNSProviderIdRequest{
|
||||||
DnsProviderId: provider.Id,
|
DnsProviderId: provider.Id,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -18,19 +18,24 @@ func (this *ProviderAction) Init() {
|
|||||||
|
|
||||||
func (this *ProviderAction) RunGet(params struct {
|
func (this *ProviderAction) RunGet(params struct {
|
||||||
ProviderId int64
|
ProviderId int64
|
||||||
|
Page int
|
||||||
|
Filter string
|
||||||
}) {
|
}) {
|
||||||
|
this.Data["pageNo"] = params.Page
|
||||||
|
this.Data["filter"] = params.Filter
|
||||||
|
|
||||||
providerResp, err := this.RPC().DNSProviderRPC().FindEnabledDNSProvider(this.AdminContext(), &pb.FindEnabledDNSProviderRequest{DnsProviderId: params.ProviderId})
|
providerResp, err := this.RPC().DNSProviderRPC().FindEnabledDNSProvider(this.AdminContext(), &pb.FindEnabledDNSProviderRequest{DnsProviderId: params.ProviderId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
provider := providerResp.DnsProvider
|
var provider = providerResp.DnsProvider
|
||||||
if provider == nil {
|
if provider == nil {
|
||||||
this.NotFound("dnsProvider", params.ProviderId)
|
this.NotFound("dnsProvider", params.ProviderId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
apiParams := maps.Map{}
|
var apiParams = maps.Map{}
|
||||||
if len(provider.ApiParamsJSON) > 0 {
|
if len(provider.ApiParamsJSON) > 0 {
|
||||||
err = json.Unmarshal(provider.ApiParamsJSON, &apiParams)
|
err = json.Unmarshal(provider.ApiParamsJSON, &apiParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -40,21 +45,10 @@ func (this *ProviderAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 本地EdgeDNS相关
|
// 本地EdgeDNS相关
|
||||||
var localEdgeDNSMap = maps.Map{}
|
localEdgeDNSMap, err := this.readEdgeDNS(provider, apiParams)
|
||||||
if provider.Type == "localEdgeDNS" {
|
if err != nil {
|
||||||
nsClusterId := apiParams.GetInt64("clusterId")
|
this.ErrorPage(err)
|
||||||
nsClusterResp, err := this.RPC().NSClusterRPC().FindEnabledNSCluster(this.AdminContext(), &pb.FindEnabledNSClusterRequest{NsClusterId: nsClusterId})
|
return
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
nsCluster := nsClusterResp.NsCluster
|
|
||||||
if nsCluster != nil {
|
|
||||||
localEdgeDNSMap = maps.Map{
|
|
||||||
"id": nsCluster.Id,
|
|
||||||
"name": nsCluster.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Data["provider"] = maps.Map{
|
this.Data["provider"] = maps.Map{
|
||||||
@@ -66,13 +60,33 @@ func (this *ProviderAction) RunGet(params struct {
|
|||||||
"localEdgeDNS": localEdgeDNSMap,
|
"localEdgeDNS": localEdgeDNSMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 域名
|
// 域名数量
|
||||||
domainsResp, err := this.RPC().DNSDomainRPC().FindAllEnabledDNSDomainsWithDNSProviderId(this.AdminContext(), &pb.FindAllEnabledDNSDomainsWithDNSProviderIdRequest{DnsProviderId: provider.Id})
|
countDomainsResp, err := this.RPC().DNSDomainRPC().CountAllDNSDomainsWithDNSProviderId(this.AdminContext(), &pb.CountAllDNSDomainsWithDNSProviderIdRequest{
|
||||||
|
DnsProviderId: params.ProviderId,
|
||||||
|
IsDeleted: params.Filter == "deleted",
|
||||||
|
IsDown: params.Filter == "down",
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
domainMaps := []maps.Map{}
|
var countDomains = countDomainsResp.Count
|
||||||
|
var page = this.NewPage(countDomains)
|
||||||
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
|
// 域名
|
||||||
|
domainsResp, err := this.RPC().DNSDomainRPC().ListBasicDNSDomainsWithDNSProviderId(this.AdminContext(), &pb.ListBasicDNSDomainsWithDNSProviderIdRequest{
|
||||||
|
DnsProviderId: params.ProviderId,
|
||||||
|
IsDeleted: params.Filter == "deleted",
|
||||||
|
IsDown: params.Filter == "down",
|
||||||
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var domainMaps = []maps.Map{}
|
||||||
for _, domain := range domainsResp.DnsDomains {
|
for _, domain := range domainsResp.DnsDomains {
|
||||||
dataUpdatedTime := ""
|
dataUpdatedTime := ""
|
||||||
if domain.DataUpdatedAt > 0 {
|
if domain.DataUpdatedAt > 0 {
|
||||||
|
|||||||
13
internal/web/actions/default/dns/providers/provider_ext.go
Normal file
13
internal/web/actions/default/dns/providers/provider_ext.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
//go:build !plus
|
||||||
|
|
||||||
|
package providers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (this *ProviderAction) readEdgeDNS(provider *pb.DNSProvider, apiParams maps.Map) (maps.Map, error) {
|
||||||
|
return maps.Map{}, nil
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package providers
|
package providers
|
||||||
|
|
||||||
@@ -68,19 +67,7 @@ func (this *UpdatePopupAction) RunGet(params struct {
|
|||||||
this.Data["types"] = typeMaps
|
this.Data["types"] = typeMaps
|
||||||
|
|
||||||
// EdgeDNS集群列表
|
// EdgeDNS集群列表
|
||||||
nsClustersResp, err := this.RPC().NSClusterRPC().FindAllEnabledNSClusters(this.AdminContext(), &pb.FindAllEnabledNSClustersRequest{})
|
this.Data["nsClusters"] = []maps.Map{}
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
nsClusterMaps := []maps.Map{}
|
|
||||||
for _, nsCluster := range nsClustersResp.NsClusters {
|
|
||||||
nsClusterMaps = append(nsClusterMaps, maps.Map{
|
|
||||||
"id": nsCluster.Id,
|
|
||||||
"name": nsCluster.Name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.Data["nsClusters"] = nsClusterMaps
|
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
@@ -109,13 +96,16 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
|||||||
ParamCloudFlareAPIKey string
|
ParamCloudFlareAPIKey string
|
||||||
ParamCloudFlareEmail string
|
ParamCloudFlareEmail string
|
||||||
|
|
||||||
// Local EdgeDNS
|
|
||||||
ParamLocalEdgeDNSClusterId int64
|
|
||||||
|
|
||||||
// CustomHTTP
|
// CustomHTTP
|
||||||
ParamCustomHTTPURL string
|
ParamCustomHTTPURL string
|
||||||
ParamCustomHTTPSecret string
|
ParamCustomHTTPSecret string
|
||||||
|
|
||||||
|
// EdgeDNS API
|
||||||
|
ParamEdgeDNSAPIHost string
|
||||||
|
ParamEdgeDNSAPIRole string
|
||||||
|
ParamEdgeDNSAPIAccessKeyId string
|
||||||
|
ParamEdgeDNSAPIAccessKeySecret string
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
CSRF *actionutils.CSRF
|
||||||
}) {
|
}) {
|
||||||
@@ -166,11 +156,20 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
|||||||
Email("请输入正确格式的邮箱地址")
|
Email("请输入正确格式的邮箱地址")
|
||||||
apiParams["apiKey"] = params.ParamCloudFlareAPIKey
|
apiParams["apiKey"] = params.ParamCloudFlareAPIKey
|
||||||
apiParams["email"] = params.ParamCloudFlareEmail
|
apiParams["email"] = params.ParamCloudFlareEmail
|
||||||
case "localEdgeDNS":
|
case "edgeDNSAPI":
|
||||||
params.Must.
|
params.Must.
|
||||||
Field("ParamLocalEdgeDNSClusterId", params.ParamLocalEdgeDNSClusterId).
|
Field("paramEdgeDNSAPIHost", params.ParamEdgeDNSAPIHost).
|
||||||
Gt(0, "请选择域名服务集群")
|
Require("请输入API地址").
|
||||||
apiParams["clusterId"] = params.ParamLocalEdgeDNSClusterId
|
Field("paramEdgeDNSAPIRole", params.ParamEdgeDNSAPIRole).
|
||||||
|
Require("请选择AccessKey类型").
|
||||||
|
Field("paramEdgeDNSAPIAccessKeyId", params.ParamEdgeDNSAPIAccessKeyId).
|
||||||
|
Require("请输入AccessKey ID").
|
||||||
|
Field("paramEdgeDNSAPIAccessKeySecret", params.ParamEdgeDNSAPIAccessKeySecret).
|
||||||
|
Require("请输入AccessKey密钥")
|
||||||
|
apiParams["host"] = params.ParamEdgeDNSAPIHost
|
||||||
|
apiParams["role"] = params.ParamEdgeDNSAPIRole
|
||||||
|
apiParams["accessKeyId"] = params.ParamEdgeDNSAPIAccessKeyId
|
||||||
|
apiParams["accessKeySecret"] = params.ParamEdgeDNSAPIAccessKeySecret
|
||||||
case "customHTTP":
|
case "customHTTP":
|
||||||
params.Must.
|
params.Must.
|
||||||
Field("paramCustomHTTPURL", params.ParamCustomHTTPURL).
|
Field("paramCustomHTTPURL", params.ParamCustomHTTPURL).
|
||||||
|
|||||||
@@ -23,36 +23,38 @@ func (this *UpdateClusterPopupAction) RunGet(params struct {
|
|||||||
}) {
|
}) {
|
||||||
this.Data["clusterId"] = params.ClusterId
|
this.Data["clusterId"] = params.ClusterId
|
||||||
|
|
||||||
dnsResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
dnsInfoResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.Data["dnsName"] = dnsResp.Name
|
this.Data["dnsName"] = dnsInfoResp.Name
|
||||||
this.Data["nodesAutoSync"] = dnsResp.NodesAutoSync
|
this.Data["nodesAutoSync"] = dnsInfoResp.NodesAutoSync
|
||||||
this.Data["serversAutoSync"] = dnsResp.ServersAutoSync
|
this.Data["serversAutoSync"] = dnsInfoResp.ServersAutoSync
|
||||||
if dnsResp.Domain != nil {
|
if dnsInfoResp.Domain != nil {
|
||||||
this.Data["domainId"] = dnsResp.Domain.Id
|
this.Data["domainId"] = dnsInfoResp.Domain.Id
|
||||||
this.Data["domain"] = dnsResp.Domain.Name
|
this.Data["domain"] = dnsInfoResp.Domain.Name
|
||||||
} else {
|
} else {
|
||||||
this.Data["domainId"] = 0
|
this.Data["domainId"] = 0
|
||||||
this.Data["domain"] = ""
|
this.Data["domain"] = ""
|
||||||
}
|
}
|
||||||
if dnsResp.Provider != nil {
|
if dnsInfoResp.Provider != nil {
|
||||||
this.Data["providerType"] = dnsResp.Provider.Type
|
this.Data["providerType"] = dnsInfoResp.Provider.Type
|
||||||
this.Data["providerId"] = dnsResp.Provider.Id
|
this.Data["providerId"] = dnsInfoResp.Provider.Id
|
||||||
} else {
|
} else {
|
||||||
this.Data["providerType"] = ""
|
this.Data["providerType"] = ""
|
||||||
this.Data["providerId"] = 0
|
this.Data["providerId"] = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dnsResp.CnameRecords) == 0 {
|
if len(dnsInfoResp.CnameRecords) == 0 {
|
||||||
this.Data["cnameRecords"] = []string{}
|
this.Data["cnameRecords"] = []string{}
|
||||||
} else {
|
} else {
|
||||||
this.Data["cnameRecords"] = dnsResp.CnameRecords
|
this.Data["cnameRecords"] = dnsInfoResp.CnameRecords
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Data["ttl"] = dnsResp.Ttl
|
this.Data["ttl"] = dnsInfoResp.Ttl
|
||||||
|
this.Data["cnameAsDomain"] = dnsInfoResp.CnameAsDomain
|
||||||
|
this.Data["includingLnNodes"] = dnsInfoResp.IncludingLnNodes
|
||||||
|
|
||||||
// 所有服务商
|
// 所有服务商
|
||||||
providerTypesResp, err := this.RPC().DNSProviderRPC().FindAllDNSProviderTypes(this.AdminContext(), &pb.FindAllDNSProviderTypesRequest{})
|
providerTypesResp, err := this.RPC().DNSProviderRPC().FindAllDNSProviderTypes(this.AdminContext(), &pb.FindAllDNSProviderTypesRequest{})
|
||||||
@@ -73,13 +75,15 @@ func (this *UpdateClusterPopupAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *UpdateClusterPopupAction) RunPost(params struct {
|
func (this *UpdateClusterPopupAction) RunPost(params struct {
|
||||||
ClusterId int64
|
ClusterId int64
|
||||||
DnsName string
|
DnsName string
|
||||||
DomainId int64
|
DomainId int64
|
||||||
NodesAutoSync bool
|
NodesAutoSync bool
|
||||||
ServersAutoSync bool
|
ServersAutoSync bool
|
||||||
CnameRecords []string
|
CnameRecords []string
|
||||||
Ttl int32
|
Ttl int32
|
||||||
|
CnameAsDomain bool
|
||||||
|
IncludingLnNodes bool
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
CSRF *actionutils.CSRF
|
||||||
@@ -108,13 +112,15 @@ func (this *UpdateClusterPopupAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterDNS(this.AdminContext(), &pb.UpdateNodeClusterDNSRequest{
|
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterDNS(this.AdminContext(), &pb.UpdateNodeClusterDNSRequest{
|
||||||
NodeClusterId: params.ClusterId,
|
NodeClusterId: params.ClusterId,
|
||||||
DnsName: params.DnsName,
|
DnsName: params.DnsName,
|
||||||
DnsDomainId: params.DomainId,
|
DnsDomainId: params.DomainId,
|
||||||
NodesAutoSync: params.NodesAutoSync,
|
NodesAutoSync: params.NodesAutoSync,
|
||||||
ServersAutoSync: params.ServersAutoSync,
|
ServersAutoSync: params.ServersAutoSync,
|
||||||
CnameRecords: params.CnameRecords,
|
CnameRecords: params.CnameRecords,
|
||||||
Ttl: params.Ttl,
|
Ttl: params.Ttl,
|
||||||
|
CnameAsDomain: params.CnameAsDomain,
|
||||||
|
IncludingLnNodes: params.IncludingLnNodes,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
this.Data["isUser"] = false
|
this.Data["isUser"] = false
|
||||||
this.Data["menu"] = "signIn"
|
this.Data["menu"] = "signIn"
|
||||||
|
|
||||||
timestamp := fmt.Sprintf("%d", time.Now().Unix())
|
var timestamp = fmt.Sprintf("%d", time.Now().Unix())
|
||||||
this.Data["token"] = stringutil.Md5(TokenSalt+timestamp) + timestamp
|
this.Data["token"] = stringutil.Md5(TokenSalt+timestamp) + timestamp
|
||||||
this.Data["from"] = params.From
|
this.Data["from"] = params.From
|
||||||
|
|
||||||
@@ -111,11 +111,11 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
if len(params.Token) <= 32 {
|
if len(params.Token) <= 32 {
|
||||||
this.Fail("请通过登录页面登录")
|
this.Fail("请通过登录页面登录")
|
||||||
}
|
}
|
||||||
timestampString := params.Token[32:]
|
var timestampString = params.Token[32:]
|
||||||
if stringutil.Md5(TokenSalt+timestampString) != params.Token[:32] {
|
if stringutil.Md5(TokenSalt+timestampString) != params.Token[:32] {
|
||||||
this.FailField("refresh", "登录页面已过期,请刷新后重试")
|
this.FailField("refresh", "登录页面已过期,请刷新后重试")
|
||||||
}
|
}
|
||||||
timestamp := types.Int64(timestampString)
|
var timestamp = types.Int64(timestampString)
|
||||||
if timestamp < time.Now().Unix()-1800 {
|
if timestamp < time.Now().Unix()-1800 {
|
||||||
this.FailField("refresh", "登录页面已过期,请刷新后重试")
|
this.FailField("refresh", "登录页面已过期,请刷新后重试")
|
||||||
}
|
}
|
||||||
@@ -157,7 +157,7 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if otpLoginResp.Login != nil && otpLoginResp.Login.IsOn {
|
if otpLoginResp.Login != nil && otpLoginResp.Login.IsOn {
|
||||||
loginParams := maps.Map{}
|
var loginParams = maps.Map{}
|
||||||
err = json.Unmarshal(otpLoginResp.Login.ParamsJSON, &loginParams)
|
err = json.Unmarshal(otpLoginResp.Login.ParamsJSON, &loginParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
@@ -169,7 +169,7 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
adminId := resp.AdminId
|
var adminId = resp.AdminId
|
||||||
params.Auth.StoreAdmin(adminId, params.Remember)
|
params.Auth.StoreAdmin(adminId, params.Remember)
|
||||||
|
|
||||||
// 记录日志
|
// 记录日志
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/lists"
|
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
"github.com/tealeg/xlsx/v3"
|
"github.com/tealeg/xlsx/v3"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -69,17 +68,13 @@ func (this *ExportExcelAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if regionResp.IpRegion != nil {
|
if regionResp.IpRegion != nil {
|
||||||
pieces := []string{}
|
regionName = regionResp.IpRegion.Summary
|
||||||
if len(regionResp.IpRegion.Country) > 0 {
|
|
||||||
pieces = append(pieces, regionResp.IpRegion.Country)
|
// remove isp from regionName
|
||||||
|
var index = strings.LastIndex(regionName, "|")
|
||||||
|
if index > 0 {
|
||||||
|
regionName = regionName[:index]
|
||||||
}
|
}
|
||||||
if len(regionResp.IpRegion.Province) > 0 && !lists.ContainsString(pieces, regionResp.IpRegion.Province) {
|
|
||||||
pieces = append(pieces, regionResp.IpRegion.Province)
|
|
||||||
}
|
|
||||||
if len(regionResp.IpRegion.City) > 0 && !lists.ContainsString(pieces, regionResp.IpRegion.City) && !lists.ContainsString(pieces, strings.TrimSuffix(regionResp.IpRegion.Province, "市")) {
|
|
||||||
pieces = append(pieces, regionResp.IpRegion.City)
|
|
||||||
}
|
|
||||||
regionName = strings.Join(pieces, " ")
|
|
||||||
|
|
||||||
if len(regionResp.IpRegion.Isp) > 0 {
|
if len(regionResp.IpRegion.Isp) > 0 {
|
||||||
ispName = regionResp.IpRegion.Isp
|
ispName = regionResp.IpRegion.Isp
|
||||||
|
|||||||
@@ -4,10 +4,8 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/lists"
|
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexAction struct {
|
type IndexAction struct {
|
||||||
@@ -72,11 +70,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if regionResp.IpRegion != nil {
|
if regionResp.IpRegion != nil {
|
||||||
pieces := []string{regionResp.IpRegion.Summary}
|
regionName = regionResp.IpRegion.Summary
|
||||||
if len(regionResp.IpRegion.Isp) > 0 && !lists.ContainsString(pieces, regionResp.IpRegion.Isp) {
|
|
||||||
pieces = append(pieces, "| "+regionResp.IpRegion.Isp)
|
|
||||||
}
|
|
||||||
regionName = strings.Join(pieces, " ")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logMaps = append(logMaps, maps.Map{
|
logMaps = append(logMaps, maps.Map{
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ func (this *AddPortPopupAction) RunGet(params struct {
|
|||||||
}) {
|
}) {
|
||||||
this.Data["from"] = params.From
|
this.Data["from"] = params.From
|
||||||
|
|
||||||
protocols := serverconfigs.AllServerProtocolsForType(params.ServerType)
|
protocols := serverconfigs.FindAllServerProtocolsForType(params.ServerType)
|
||||||
if len(params.Protocol) > 0 {
|
if len(params.Protocol) > 0 {
|
||||||
result := []maps.Map{}
|
result := []maps.Map{}
|
||||||
for _, p := range protocols {
|
for _, p := range protocols {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func (this *AddServerNamePopupAction) RunPost(params struct {
|
|||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
}) {
|
}) {
|
||||||
if params.Mode == "single" {
|
if params.Mode == "single" {
|
||||||
var serverName = params.ServerName
|
var serverName = strings.ToLower(params.ServerName)
|
||||||
|
|
||||||
// 去除空格
|
// 去除空格
|
||||||
serverName = regexp.MustCompile(`\s+`).ReplaceAllString(serverName, "")
|
serverName = regexp.MustCompile(`\s+`).ReplaceAllString(serverName, "")
|
||||||
@@ -72,6 +72,9 @@ func (this *AddServerNamePopupAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 转成小写
|
||||||
|
serverName = strings.ToLower(serverName)
|
||||||
|
|
||||||
serverNames = append(serverNames, serverName)
|
serverNames = append(serverNames, serverName)
|
||||||
}
|
}
|
||||||
this.Data["serverName"] = maps.Map{
|
this.Data["serverName"] = maps.Map{
|
||||||
|
|||||||
@@ -36,15 +36,11 @@ func (this *DeleteAction) RunPost(params struct {
|
|||||||
this.Fail("此证书正在被某些API节点引用,请先修改API节点后再删除")
|
this.Fail("此证书正在被某些API节点引用,请先修改API节点后再删除")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 是否正在被用户节点使用
|
err = this.filterDelete(params.CertId)
|
||||||
countResp, err = this.RPC().UserNodeRPC().CountAllEnabledUserNodesWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledUserNodesWithSSLCertIdRequest{SslCertId: params.CertId})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if countResp.Count > 0 {
|
|
||||||
this.Fail("此证书正在被某些用户节点引用,请先修改用户节点后再删除")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = this.RPC().SSLCertRPC().DeleteSSLCert(this.AdminContext(), &pb.DeleteSSLCertRequest{SslCertId: params.CertId})
|
_, err = this.RPC().SSLCertRPC().DeleteSSLCert(this.AdminContext(), &pb.DeleteSSLCertRequest{SslCertId: params.CertId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
8
internal/web/actions/default/servers/certs/delete_ext.go
Normal file
8
internal/web/actions/default/servers/certs/delete_ext.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
//go:build !plus
|
||||||
|
|
||||||
|
package certs
|
||||||
|
|
||||||
|
func (this *DeleteAction) filterDelete(certId int64) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -65,7 +64,7 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
DefaultDomain string
|
DefaultDomain string
|
||||||
}) {
|
}) {
|
||||||
// 创建日志
|
// 创建日志
|
||||||
defer this.CreateLog(oplogs.LevelInfo, "保存代理服务全局配置")
|
defer this.CreateLog(oplogs.LevelInfo, "保存网站服务全局配置")
|
||||||
|
|
||||||
if len(params.GlobalConfigJSON) == 0 {
|
if len(params.GlobalConfigJSON) == 0 {
|
||||||
this.Fail("错误的配置信息,请刷新当前页面后重试")
|
this.Fail("错误的配置信息,请刷新当前页面后重试")
|
||||||
@@ -84,27 +83,6 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
allowMismatchDomains = append(allowMismatchDomains, domain)
|
allowMismatchDomains = append(allowMismatchDomains, domain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
globalConfig.HTTPAll.AllowMismatchDomains = allowMismatchDomains
|
|
||||||
|
|
||||||
// 不匹配域名的动作
|
|
||||||
switch params.DomainMismatchAction {
|
|
||||||
case "close":
|
|
||||||
globalConfig.HTTPAll.DomainMismatchAction = &serverconfigs.DomainMismatchAction{
|
|
||||||
Code: "close",
|
|
||||||
Options: nil,
|
|
||||||
}
|
|
||||||
case "page":
|
|
||||||
if params.DomainMismatchActionPageStatusCode <= 0 {
|
|
||||||
params.DomainMismatchActionPageStatusCode = 404
|
|
||||||
}
|
|
||||||
globalConfig.HTTPAll.DomainMismatchAction = &serverconfigs.DomainMismatchAction{
|
|
||||||
Code: "page",
|
|
||||||
Options: maps.Map{
|
|
||||||
"statusCode": params.DomainMismatchActionPageStatusCode,
|
|
||||||
"contentHTML": params.DomainMismatchActionPageContentHTML,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TCP端口范围
|
// TCP端口范围
|
||||||
if params.TcpAllPortRangeMin < 1024 {
|
if params.TcpAllPortRangeMin < 1024 {
|
||||||
|
|||||||
@@ -36,21 +36,21 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
this.NotFound("firewallPolicy", params.FirewallPolicyId)
|
this.NotFound("firewallPolicy", params.FirewallPolicyId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
selectedCountryIds := []int64{}
|
var selectedCountryIds = []int64{}
|
||||||
if policyConfig.Inbound != nil && policyConfig.Inbound.Region != nil {
|
if policyConfig.Inbound != nil && policyConfig.Inbound.Region != nil {
|
||||||
selectedCountryIds = policyConfig.Inbound.Region.DenyCountryIds
|
selectedCountryIds = policyConfig.Inbound.Region.DenyCountryIds
|
||||||
}
|
}
|
||||||
|
|
||||||
countriesResp, err := this.RPC().RegionCountryRPC().FindAllEnabledRegionCountries(this.AdminContext(), &pb.FindAllEnabledRegionCountriesRequest{})
|
countriesResp, err := this.RPC().RegionCountryRPC().FindAllRegionCountries(this.AdminContext(), &pb.FindAllRegionCountriesRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
countryMaps := []maps.Map{}
|
var countryMaps = []maps.Map{}
|
||||||
for _, country := range countriesResp.RegionCountries {
|
for _, country := range countriesResp.RegionCountries {
|
||||||
countryMaps = append(countryMaps, maps.Map{
|
countryMaps = append(countryMaps, maps.Map{
|
||||||
"id": country.Id,
|
"id": country.Id,
|
||||||
"name": country.Name,
|
"name": country.DisplayName,
|
||||||
"letter": strings.ToUpper(string(country.Pinyin[0][0])),
|
"letter": strings.ToUpper(string(country.Pinyin[0][0])),
|
||||||
"isChecked": lists.ContainsInt64(selectedCountryIds, country.Id),
|
"isChecked": lists.ContainsInt64(selectedCountryIds, country.Id),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -37,23 +37,23 @@ func (this *ProvincesAction) RunGet(params struct {
|
|||||||
this.NotFound("firewallPolicy", params.FirewallPolicyId)
|
this.NotFound("firewallPolicy", params.FirewallPolicyId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
selectedProvinceIds := []int64{}
|
var selectedProvinceIds = []int64{}
|
||||||
if policyConfig.Inbound != nil && policyConfig.Inbound.Region != nil {
|
if policyConfig.Inbound != nil && policyConfig.Inbound.Region != nil {
|
||||||
selectedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
|
selectedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
|
||||||
}
|
}
|
||||||
|
|
||||||
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllEnabledRegionProvincesWithCountryId(this.AdminContext(), &pb.FindAllEnabledRegionProvincesWithCountryIdRequest{
|
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithRegionCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithRegionCountryIdRequest{
|
||||||
RegionCountryId: int64(ChinaCountryId),
|
RegionCountryId: int64(ChinaCountryId),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
provinceMaps := []maps.Map{}
|
var provinceMaps = []maps.Map{}
|
||||||
for _, province := range provincesResp.RegionProvinces {
|
for _, province := range provincesResp.RegionProvinces {
|
||||||
provinceMaps = append(provinceMaps, maps.Map{
|
provinceMaps = append(provinceMaps, maps.Map{
|
||||||
"id": province.Id,
|
"id": province.Id,
|
||||||
"name": province.Name,
|
"name": province.DisplayName,
|
||||||
"isChecked": lists.ContainsInt64(selectedProvinceIds, province.Id),
|
"isChecked": lists.ContainsInt64(selectedProvinceIds, province.Id),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,9 +80,9 @@ func (this *UpdateIPPopupAction) RunPost(params struct {
|
|||||||
|
|
||||||
var ipToLong uint64
|
var ipToLong uint64
|
||||||
if len(params.IpTo) > 0 && !utils.IsIPv4(params.IpTo) {
|
if len(params.IpTo) > 0 && !utils.IsIPv4(params.IpTo) {
|
||||||
ipToLong = utils.IP2Long(params.IpTo)
|
|
||||||
this.Fail("请输入正确的结束IP")
|
this.Fail("请输入正确的结束IP")
|
||||||
}
|
}
|
||||||
|
ipToLong = utils.IP2Long(params.IpTo)
|
||||||
|
|
||||||
if ipFromLong > 0 && ipToLong > 0 && ipFromLong > ipToLong {
|
if ipFromLong > 0 && ipToLong > 0 && ipFromLong > ipToLong {
|
||||||
params.IpTo, params.IpFrom = params.IpFrom, params.IpTo
|
params.IpTo, params.IpFrom = params.IpFrom, params.IpTo
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package servergrouputils
|
package servergrouputils
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,10 @@ func (this *SettingAction) RunPost(params struct {
|
|||||||
FollowRedirects: reverseProxyConfig.FollowRedirects,
|
FollowRedirects: reverseProxyConfig.FollowRedirects,
|
||||||
ProxyProtocolJSON: proxyProtocolJSON,
|
ProxyProtocolJSON: proxyProtocolJSON,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,5 +24,4 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
} else {
|
} else {
|
||||||
this.RedirectURL("/servers/groups/group/settings/httpReverseProxy?groupId=" + types.String(params.GroupId))
|
this.RedirectURL("/servers/groups/group/settings/httpReverseProxy?groupId=" + types.String(params.GroupId))
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,6 +109,10 @@ func (this *SettingAction) RunPost(params struct {
|
|||||||
FollowRedirects: reverseProxyConfig.FollowRedirects,
|
FollowRedirects: reverseProxyConfig.FollowRedirects,
|
||||||
ProxyProtocolJSON: proxyProtocolJSON,
|
ProxyProtocolJSON: proxyProtocolJSON,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,8 +96,12 @@ func (this *SettingAction) RunPost(params struct {
|
|||||||
StripPrefix: reverseProxyConfig.StripPrefix,
|
StripPrefix: reverseProxyConfig.StripPrefix,
|
||||||
AutoFlush: reverseProxyConfig.AutoFlush,
|
AutoFlush: reverseProxyConfig.AutoFlush,
|
||||||
AddHeaders: reverseProxyConfig.AddHeaders,
|
AddHeaders: reverseProxyConfig.AddHeaders,
|
||||||
FollowRedirects: reverseProxyConfig.FollowRedirects,
|
FollowRedirects: reverseProxyConfig.FollowRedirects,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,16 +46,16 @@ func (this *CountriesAction) RunGet(params struct {
|
|||||||
selectedCountryIds = policyConfig.Inbound.Region.DenyCountryIds
|
selectedCountryIds = policyConfig.Inbound.Region.DenyCountryIds
|
||||||
}
|
}
|
||||||
|
|
||||||
countriesResp, err := this.RPC().RegionCountryRPC().FindAllEnabledRegionCountries(this.AdminContext(), &pb.FindAllEnabledRegionCountriesRequest{})
|
countriesResp, err := this.RPC().RegionCountryRPC().FindAllRegionCountries(this.AdminContext(), &pb.FindAllRegionCountriesRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
countryMaps := []maps.Map{}
|
countryMaps := []maps.Map{}
|
||||||
for _, country := range countriesResp.Countries {
|
for _, country := range countriesResp.RegionCountries {
|
||||||
countryMaps = append(countryMaps, maps.Map{
|
countryMaps = append(countryMaps, maps.Map{
|
||||||
"id": country.Id,
|
"id": country.Id,
|
||||||
"name": country.Name,
|
"name": country.DisplayName,
|
||||||
"letter": strings.ToUpper(string(country.Pinyin[0][0])),
|
"letter": strings.ToUpper(string(country.Pinyin[0][0])),
|
||||||
"isChecked": lists.ContainsInt64(selectedCountryIds, country.Id),
|
"isChecked": lists.ContainsInt64(selectedCountryIds, country.Id),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -46,18 +46,18 @@ func (this *ProvincesAction) RunGet(params struct {
|
|||||||
selectedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
|
selectedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
|
||||||
}
|
}
|
||||||
|
|
||||||
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllEnabledRegionProvincesWithCountryId(this.AdminContext(), &pb.FindAllEnabledRegionProvincesWithCountryIdRequest{
|
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithRegionCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithRegionCountryIdRequest{
|
||||||
CountryId: int64(ChinaCountryId),
|
RegionCountryId: int64(ChinaCountryId),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
provinceMaps := []maps.Map{}
|
provinceMaps := []maps.Map{}
|
||||||
for _, province := range provincesResp.Provinces {
|
for _, province := range provincesResp.RegionProvinces {
|
||||||
provinceMaps = append(provinceMaps, maps.Map{
|
provinceMaps = append(provinceMaps, maps.Map{
|
||||||
"id": province.Id,
|
"id": province.Id,
|
||||||
"name": province.Name,
|
"name": province.DisplayName,
|
||||||
"isChecked": lists.ContainsInt64(selectedProvinceIds, province.Id),
|
"isChecked": lists.ContainsInt64(selectedProvinceIds, province.Id),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user