Compare commits

...

121 Commits

Author SHA1 Message Date
刘祥超
15a11c384b 优化代码 2022-09-25 20:34:43 +08:00
刘祥超
57b8496d89 更新components.js 2022-09-25 10:34:12 +08:00
刘祥超
7bbe44f5d2 优化代码 2022-09-25 10:33:10 +08:00
刘祥超
ac11ab0431 缓存条件增加”忽略URI参数“选项 2022-09-24 15:13:35 +08:00
刘祥超
12e352964c 默认支持206 Partial Content 2022-09-24 14:40:34 +08:00
刘祥超
7daefc4384 优化代码 2022-09-24 14:06:41 +08:00
刘祥超
29541becd0 添加Header的时候自动去除Header后多余的冒号 2022-09-23 19:00:51 +08:00
刘祥超
ef6dc82f88 优化代码 2022-09-23 11:09:21 +08:00
刘祥超
6d66d93180 智能DNS访问日志增加只记录失败查询选项 2022-09-22 18:41:43 +08:00
刘祥超
3ded17b920 优化防盗链选项说明文字 2022-09-22 17:55:58 +08:00
刘祥超
d35651f570 增加防盗链功能 2022-09-22 16:33:35 +08:00
刘祥超
235300d034 修改反向代理等文字 2022-09-22 15:27:23 +08:00
刘祥超
2f7ebf5166 优化代码 2022-09-21 13:49:02 +08:00
刘祥超
4819cc87c6 删除不必要的文件 2022-09-20 18:22:13 +08:00
刘祥超
c5da383d1e 更新components.js 2022-09-19 09:50:03 +08:00
刘祥超
2da17329fa 创建节点时尝试自动从节点名称中读取IP 2022-09-18 14:57:37 +08:00
刘祥超
70d84acf76 在节点手动安装页显示节点安装文件下载链接 2022-09-18 12:38:32 +08:00
刘祥超
fef99a0023 优化代码/DNS域名增加分页 2022-09-18 10:22:58 +08:00
刘祥超
76d0935e8f 可以设置是否自动安装nftables 2022-09-17 21:04:45 +08:00
刘祥超
42dfe5ada9 缓存的URL类型文字从“前缀”改成“目录” 2022-09-17 19:26:27 +08:00
刘祥超
ef136c25e1 域名解析域名和记录名中支持中文 2022-09-17 16:50:25 +08:00
刘祥超
4251635a8a 集群增加是否远程启动选项 2022-09-17 15:11:40 +08:00
刘祥超
13f00104dd 健康检查设置域名时检查域名是否存在 2022-09-17 11:38:04 +08:00
刘祥超
b0b82b29c1 集群设置--DNS设置页显示DNS账号名 2022-09-17 10:59:18 +08:00
刘祥超
e0d43ad3d9 节点即使离线后仍然在运行状态中显示版本、主程序位置等信息 2022-09-17 10:25:40 +08:00
刘祥超
ae15115af7 创建集群时增加“只允许绑定的域名访问”选项 2022-09-16 19:33:57 +08:00
刘祥超
a2890c6cb0 集群设置中增加服务设置 2022-09-16 18:41:04 +08:00
刘祥超
2b00ece07f 访问日志中增加源站状态码 2022-09-16 10:07:21 +08:00
刘祥超
2e3c34571f 删除不必要的文件 2022-09-15 19:03:30 +08:00
刘祥超
b8b10b5176 集群增加自动同步时钟选项 2022-09-15 15:57:53 +08:00
刘祥超
e6e62bbd24 域名和记录名中可以使用大写 2022-09-14 19:48:23 +08:00
刘祥超
05e9bbf1d6 添加域名窗口中提示可以添加泛域名 2022-09-14 09:24:27 +08:00
刘祥超
bf94c2395f 可以隐藏CDN功能菜单 2022-09-13 19:54:31 +08:00
刘祥超
4a749ca345 优化GRPC参数 2022-09-13 10:48:54 +08:00
刘祥超
80ffe6c9a3 实现DNS域名验证 2022-09-10 16:13:31 +08:00
刘祥超
5414b5a8f9 优化提示文字 2022-09-09 10:33:16 +08:00
刘祥超
e3ba85a326 修改管理界面设置中的时区时同时也会应用到API节点 2022-09-09 10:27:10 +08:00
刘祥超
154fa69dbb 优化安装时跟端口相关的提示 2022-09-08 19:45:23 +08:00
刘祥超
76c44973e9 域名解析增加EdgeDNS API 2022-09-08 19:36:37 +08:00
刘祥超
26fdc82cc1 创建集群的时候可以设置DNS记录的默认TTL 2022-09-08 11:02:19 +08:00
刘祥超
dcc587182c 优化文字提示 2022-09-08 11:00:44 +08:00
刘祥超
7cee1ff5ff 访问日志里以标签的形式显示中文域名 2022-09-07 17:02:40 +08:00
刘祥超
78b8e3bf0b API节点在启动时提示“API节点正在启动,请耐心等待完成” 2022-09-07 15:57:06 +08:00
刘祥超
bd4c014c12 增加edge-admin upgrade命令 2022-09-06 21:19:37 +08:00
刘祥超
daa263cd68 将版本修改为0.5.3 2022-09-06 09:24:02 +08:00
刘祥超
e2965d39af 将版本修改为0.5.2.1 2022-09-05 16:04:51 +08:00
刘祥超
8279d15ebb 将版本修改为0.5.3 2022-09-05 11:02:17 +08:00
刘祥超
9731fa35d8 生成components.js 2022-09-04 09:31:50 +08:00
刘祥超
53be4db22b 缓存条件--简单条件增加参数匹配 2022-09-03 19:25:08 +08:00
刘祥超
0202fa2ca3 优化缓存条件设置交互 2022-09-03 19:15:30 +08:00
刘祥超
d5262b5474 简化缓存条件设置 2022-09-03 18:14:34 +08:00
刘祥超
cb2e1d54c2 优化文字提示 2022-09-02 16:34:37 +08:00
刘祥超
6392297a27 修复因URL中含有搜索引擎关键词而导致页面403的问题 2022-09-02 09:26:50 +08:00
刘祥超
6001d4eba3 更新components.js和一处绿色色值 2022-09-01 09:07:28 +08:00
刘祥超
79588e4bbc DDoS防护增加秒级连接速率限制 2022-08-31 10:00:55 +08:00
刘祥超
2b21c38382 访问控制修改为访问鉴权 2022-08-30 17:04:02 +08:00
刘祥超
481d25845e 修复CSRF可能导致访问控制自动保存失败的问题 2022-08-30 12:08:42 +08:00
刘祥超
e0f8bfe283 优化路由规则中访问控制功能 2022-08-30 11:43:49 +08:00
刘祥超
d2ecb01358 修复服务访问控制页面可能空白的问题 2022-08-30 11:42:40 +08:00
刘祥超
316e793b1e 优化访问控制,将“认证”两字改为“鉴权” 2022-08-30 11:22:54 +08:00
刘祥超
6df6809ab3 优化代码 2022-08-29 09:20:46 +08:00
刘祥超
c71f892601 创建用户的时候,可以设置开通默认功能还是全部功能 2022-08-28 20:21:57 +08:00
刘祥超
d0b5a16ce7 更新components.js 2022-08-28 20:01:29 +08:00
刘祥超
84638d3228 优化代码 2022-08-28 15:51:55 +08:00
刘祥超
bb21a2aa5f 优化代码 2022-08-28 11:07:21 +08:00
刘祥超
c37c948129 优化表头排序图标上文字提示 2022-08-27 18:45:07 +08:00
刘祥超
5155476dd7 对缓存策略中的句柄和sendfile增加设置警告 2022-08-27 18:39:36 +08:00
刘祥超
7ef4f60309 服务列表带宽使用新的算法 2022-08-27 18:37:44 +08:00
刘祥超
b0865cbbdc 可以修改服务的CNAME 2022-08-26 19:51:07 +08:00
刘祥超
990c1070e2 DDoS防护增加单IP TCP新连接速率黑名单 2022-08-26 11:32:00 +08:00
刘祥超
65bdd413eb Ln节点可以指定访问IP 2022-08-25 20:36:51 +08:00
刘祥超
60fa35eb73 集群DNS设置中增加”包含Ln节点“选项 2022-08-25 19:18:34 +08:00
刘祥超
32cfd5c233 节点运行日志可以按照节点ID设置为已读 2022-08-25 18:27:15 +08:00
刘祥超
7852495527 优化代码 2022-08-25 16:02:26 +08:00
刘祥超
3679a78f47 WAF增加Javascript cookie验证 2022-08-25 15:35:16 +08:00
刘祥超
6b21568408 优化文字提示 2022-08-25 12:02:48 +08:00
刘祥超
04a5aa41d7 浏览访问日志时自动用点符号标记有数据的分表 2022-08-25 11:36:18 +08:00
刘祥超
fea1a2199c WAF cc2阈值设置太低时提示用户 2022-08-25 09:26:06 +08:00
刘祥超
9c8492efb9 增加测试用例 2022-08-25 09:25:52 +08:00
刘祥超
20b89a8ddd 相关区域名称可以显示别名 2022-08-23 19:15:44 +08:00
刘祥超
5a8e281fb1 优化代码 2022-08-23 14:55:06 +08:00
刘祥超
a9bb413199 NS节点基本的DDoS防护 2022-08-22 15:12:10 +08:00
刘祥超
428d8ab1b1 折叠访问日志选项 2022-08-22 11:16:01 +08:00
刘祥超
c2675bcdb6 优化代码 2022-08-21 20:47:29 +08:00
刘祥超
1fe228e4c0 连接API时,自动将本地的API节点地址转换为回路地址 2022-08-20 20:33:28 +08:00
刘祥超
c5a6497f10 优化代码 2022-08-20 20:31:00 +08:00
刘祥超
f25a82585f 访问数据看板时自动初始化左侧菜单Badge 2022-08-18 09:33:14 +08:00
刘祥超
01209b66ac 对运行日志和IP名单进行操作时,及时更新左侧菜单Badge 2022-08-18 09:28:09 +08:00
刘祥超
4e19817d6f 版本修改为0.5.2 2022-08-17 18:59:37 +08:00
刘祥超
a48adff8ac 版本修改为0.5.1 2022-08-15 19:38:31 +08:00
刘祥超
ab3b32fda1 优化代码 2022-08-14 20:03:31 +08:00
刘祥超
cafab78ab4 新版IP库管理阶段性提交(未完成) 2022-08-13 23:55:35 +08:00
刘祥超
2d497dee7d 自动纠正API节点相关地址填写的常见错误 2022-08-11 18:33:46 +08:00
刘祥超
280ecd9aea 优化代码 2022-08-11 15:54:09 +08:00
刘祥超
3a980a3bc0 删除不必要的文件 2022-08-11 15:28:24 +08:00
刘祥超
556a5bdd4e 优化代码 2022-08-11 15:25:58 +08:00
刘祥超
eca26a345f generate components.js 2022-08-09 21:04:30 +08:00
刘祥超
eacff7232d 更新components.js 2022-08-08 16:26:12 +08:00
刘祥超
3c071db207 优化文字 2022-08-08 16:16:48 +08:00
刘祥超
6609c56063 页面支持DNS.LA(商业版本可用) 2022-08-07 21:18:21 +08:00
刘祥超
f7ae3de914 修改版本号为0.5.0 2022-08-07 19:02:28 +08:00
刘祥超
d82bc4e77e 缓存条件增加If-None-Match和If-Modified-Since是否回源选项 2022-08-07 16:36:41 +08:00
刘祥超
31e1df0afd 增加刷新管理界面配置函数 2022-08-07 14:56:20 +08:00
刘祥超
700e9236f9 优化代码 2022-08-06 20:28:51 +08:00
刘祥超
ee1e62aff0 优化代码 2022-08-05 21:05:49 +08:00
刘祥超
aa0c38d66f 优化代码 2022-08-05 14:38:56 +08:00
刘祥超
4e4d9e33f0 修复运行日志菜单未读数字可能不会消失的问题 2022-08-04 18:48:50 +08:00
刘祥超
f78daa98bc 删除证书之前检查是否正在被NS集群使用 2022-08-04 16:26:34 +08:00
刘祥超
dad8802fb0 优化代码 2022-08-04 11:51:34 +08:00
刘祥超
529b7041e7 优化代码 2022-08-03 21:15:12 +08:00
刘祥超
5de1eecf92 TCP源站也支持专属域名项 2022-08-03 15:28:55 +08:00
刘祥超
08ee301f89 优化代码 2022-08-03 12:20:24 +08:00
刘祥超
4154904b21 优化代码 2022-08-03 10:44:48 +08:00
刘祥超
79282809e3 优化分页样式 2022-07-31 19:56:32 +08:00
刘祥超
108c2533c2 添加域名时自动将域名转换为小写 2022-07-30 16:17:05 +08:00
刘祥超
fd7309cd17 优化路由规则界面 2022-07-30 10:43:53 +08:00
刘祥超
c5f871edf6 路由规则支持请求限制 2022-07-29 11:38:31 +08:00
刘祥超
3f2d2b238d EdgeDNS:访问日志增加集群和记录类型筛选 2022-07-27 20:20:04 +08:00
刘祥超
e6a30b99d3 优化代码 2022-07-27 16:55:19 +08:00
刘祥超
08ce2b7799 修改版本号为0.4.11 2022-07-26 08:57:04 +08:00
刘祥超
dbe7336f32 改进文字提示 2022-07-26 08:56:37 +08:00
357 changed files with 7585 additions and 5178 deletions

BIN
cmd/edge-admin/edge-admin Executable file

Binary file not shown.

View File

@@ -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()
}) })
} }

View File

@@ -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()

View File

@@ -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,

View File

@@ -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)
} }

View File

@@ -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()

View File

@@ -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)
} }

View File

@@ -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
} }

View File

@@ -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)

View File

@@ -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
} }

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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
} }

View File

@@ -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
}

View File

@@ -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
}
}

View File

@@ -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())
} }

View File

@@ -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
View 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)
}

View 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"))
}

View File

@@ -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

View File

@@ -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
} }

View File

@@ -1,4 +1,4 @@
// +build !linux,!windows //go:build !linux && !windows
package utils package utils

View File

@@ -1,4 +1,4 @@
// +build windows //go:build windows
package utils package utils

View File

@@ -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

View 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
}

View 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())
}

View 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
}

View 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)
}
}

View File

@@ -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)+

View File

@@ -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 + `

View File

@@ -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{})

View File

@@ -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,

View File

@@ -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()

View File

@@ -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", "错误的访问地址")

View File

@@ -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{}

View File

@@ -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)
}

View File

@@ -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()
} }

View File

@@ -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").

View File

@@ -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,

View File

@@ -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()
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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)

View File

@@ -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()
}) })

View File

@@ -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": "-",
}) })

View File

@@ -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

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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()
} }

View File

@@ -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()
} }

View File

@@ -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()
} }

View File

@@ -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()
} }

View File

@@ -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()
} }

View File

@@ -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

View File

@@ -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).

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -43,6 +43,9 @@ func (this *RestartLocalAPINodeAction) RunPost(params struct {
} }
} }
// 停止1秒等待命令运行完毕
time.Sleep(1 * time.Second)
// 检查是否已启动 // 检查是否已启动
var countTries = 120 var countTries = 120
for { for {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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
} }
} }

View File

@@ -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 {

View File

@@ -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
} }

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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).

View File

@@ -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 {

View File

@@ -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 {

View 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
}

View File

@@ -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).

View File

@@ -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)

View File

@@ -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)
// 记录日志 // 记录日志

View File

@@ -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

View File

@@ -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{

View File

@@ -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 {

View File

@@ -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{

View File

@@ -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 {

View 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
}

View File

@@ -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 {

View File

@@ -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),
}) })

View File

@@ -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),
}) })
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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()
} }

View File

@@ -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
} }

View File

@@ -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()
} }

View File

@@ -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()
} }

View File

@@ -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),
}) })

View File

@@ -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