Skip to content

Commit dafeab8

Browse files
feat: Add Node File Exchange (#8407)
1 parent d10d83b commit dafeab8

28 files changed

Lines changed: 259 additions & 41 deletions

File tree

agent/app/service/file.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ func (f *FileService) GetPathByType(pathType string) string {
513513
if pathType == "websiteDir" {
514514
value, _ := settingRepo.GetValueByKey("WEBSITE_DIR")
515515
if value == "" {
516-
return path.Join(global.Dir.BaseDir, "www")
516+
return path.Join(global.Dir.BaseDir, "1panel", "www")
517517
}
518518
return value
519519
}

agent/init/dir/dir.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func Init() {
1515
global.Dir.BaseDir, _ = fileOp.CreateDirWithPath(true, baseDir)
1616
global.Dir.DataDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel"))
1717
global.Dir.DbDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/db"))
18-
global.Dir.LogDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/log"))
18+
global.Dir.LogDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/log/task"))
1919
global.Dir.TmpDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/tmp"))
2020

2121
global.Dir.AppDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/apps"))

agent/utils/files/fileinfo.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,6 @@ func sortFileList(list []FileSearchInfo, sortBy, sortOrder string) {
217217
}
218218

219219
func (f *FileInfo) listChildren(option FileOption) error {
220-
afs := &afero.Afero{Fs: f.Fs}
221220
var (
222221
files []FileSearchInfo
223222
err error
@@ -230,7 +229,7 @@ func (f *FileInfo) listChildren(option FileOption) error {
230229
return err
231230
}
232231
} else {
233-
files, err = f.getFiles(afs, option)
232+
files, err = f.getFiles(option)
234233
if err != nil {
235234
return err
236235
}
@@ -261,21 +260,24 @@ func (f *FileInfo) listChildren(option FileOption) error {
261260
return nil
262261
}
263262

264-
func (f *FileInfo) getFiles(afs *afero.Afero, option FileOption) ([]FileSearchInfo, error) {
265-
dirFiles, err := afs.ReadDir(f.Path)
263+
func (f *FileInfo) getFiles(option FileOption) ([]FileSearchInfo, error) {
264+
infos, err := os.ReadDir(f.Path)
266265
if err != nil {
267266
return nil, err
268267
}
269-
270268
var (
271269
dirs []FileSearchInfo
272270
fileList []FileSearchInfo
273271
)
274272

275-
for _, file := range dirFiles {
273+
for _, file := range infos {
274+
fileInfo, err := file.Info()
275+
if err != nil {
276+
continue
277+
}
276278
info := FileSearchInfo{
277279
Path: f.Path,
278-
FileInfo: file,
280+
FileInfo: fileInfo,
279281
}
280282
if file.IsDir() {
281283
dirs = append(dirs, info)

core/app/task/task.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,13 @@ const (
4848
TaskUpgrade = "TaskUpgrade"
4949
TaskAddNode = "TaskAddNode"
5050
TaskSync = "TaskSync"
51+
TaskRsync = "TaskRsync"
5152
)
5253

5354
const (
5455
TaskScopeSystem = "System"
5556
TaskScopeScript = "Script"
56-
)
57-
58-
const (
59-
TaskSuccess = "Success"
60-
TaskFailed = "Failed"
57+
TaskScopeNodeFile = "NodeFile"
6158
)
6259

6360
func GetTaskName(resourceName, operate, scope string) string {
@@ -72,7 +69,7 @@ func NewTask(name, operate, taskScope, taskID string, resourceID uint) (*Task, e
7269
if taskID == "" {
7370
taskID = uuid.New().String()
7471
}
75-
logItem := path.Join(global.CONF.Base.InstallDir, "1panel/log")
72+
logItem := path.Join(global.CONF.Base.InstallDir, "1panel/log/task")
7673
logDir := path.Join(logItem, taskScope)
7774
if _, err := os.Stat(logDir); os.IsNotExist(err) {
7875
if err = os.MkdirAll(logDir, constant.DirPerm); err != nil {

core/i18n/lang/zh.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,12 @@ UserInfoAddr: "面板地址:"
172172
UserInfoPassHelp: "提示:修改密码可执行命令:"
173173
DBConnErr: "错误:初始化数据库连接失败,{{ .err }}"
174174
SystemVersion: "版本:"
175-
SystemMode: "模式:"
175+
SystemMode: "模式:"
176+
177+
#exchange
178+
LocalNodeIpFailed: "无法获取主节点 IP ,请编辑主节点增加 IP 地址和 SSH 认证信息"
179+
HandlePrivateKey: "处理节点私钥"
180+
HandlePublicKey: "处理节点公钥"
181+
ExchangeFile: "开始从 {{ .source }} 节点同步 {{ .sourcePath }} 到 {{ .dest }} 节点 {{ .destPath }}"
182+
TaskRsync: "同步"
183+
NodeFile: "节点文件"

core/init/migration/helper/menu.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ func LoadMenus() string {
4040
{ID: "111", Disabled: false, Title: "xpack.node.nodeManagement", IsShow: true, Label: "Node", Path: "/xpack/node"},
4141
{ID: "113", Disabled: false, Title: "xpack.monitor.name", IsShow: true, Label: "MonitorDashboard", Path: "/xpack/monitor/dashboard"},
4242
{ID: "114", Disabled: false, Title: "xpack.tamper.tamper", IsShow: true, Label: "Tamper", Path: "/xpack/tamper"},
43+
{ID: "117", Disabled: false, Title: "xpack.exchange.exchange", IsShow: true, Label: "FileExange", Path: "/xpack/exchange/file"},
4344
{ID: "116", Disabled: false, Title: "xpack.alert.alert", IsShow: true, Label: "XAlertDashboard", Path: "/xpack/alert/dashboard"},
4445
{ID: "115", Disabled: false, Title: "xpack.setting.setting", IsShow: true, Label: "XSetting", Path: "/xpack/setting"},
4546
}},

core/init/migration/migrations/init.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ var InitSetting = &gormigrate.Migration{
9595
return err
9696
}
9797
val := `{"id":"1","label":"/xpack","isCheck":true,"title":"xpack.menu","children":[{"id":"2","label":"Dashboard","isCheck":true,"title":"xpack.waf.name","path":"/xpack/waf/dashboard"},{"id":"3","label":"Tamper","isCheck":true,"title":"xpack.tamper.tamper","path":"/xpack/tamper"},{"id":"4","label":"GPU","isCheck":true,"title":"xpack.gpu.gpu","path":"/xpack/gpu"},{"id":"5","label":"XSetting","isCheck":true,"title":"xpack.setting.setting","path":"/xpack/setting"},{"id":"6","label":"MonitorDashboard","isCheck":true,"title":"xpack.monitor.name","path":"/xpack/monitor/dashboard"},{"id":"7","label":"XAlertDashboard","isCheck":true,"title":"xpack.alert.alert","path":"/xpack/alert/dashboard"},{"id":"8","label":"Node","isCheck":true,"title":"xpack.node.nodeManagement","path":"/xpack/node"}]}`
98-
if err := tx.Create(&model.Setting{Key: "XpackHideMenu", Value: val}).Error; err != nil {
98+
if err := tx.Create(&model.Setting{Key: "HideMenu", Value: val}).Error; err != nil {
9999
return err
100100
}
101101

@@ -303,9 +303,9 @@ var AddMFAInterval = &gormigrate.Migration{
303303
}
304304

305305
var UpdateXpackHideMemu = &gormigrate.Migration{
306-
ID: "20250227-update-xpack-hide-menu",
306+
ID: "20250414-update-xpack-hide-menu",
307307
Migrate: func(tx *gorm.DB) error {
308-
if err := tx.Model(&model.Setting{}).Where("key = ?", "XpackHideMenu").Updates(map[string]interface{}{"key": "HideMenu", "value": helper.LoadMenus()}).Error; err != nil {
308+
if err := tx.Model(&model.Setting{}).Where("key = ?", "HideMenu").Updates(map[string]interface{}{"key": "HideMenu", "value": helper.LoadMenus()}).Error; err != nil {
309309
return err
310310
}
311311
return nil

core/init/router/proxy.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,6 @@ import (
1919
"github.com/gin-gonic/gin"
2020
)
2121

22-
var wsUrl = map[string]struct{}{
23-
"/api/v2/process/ws": {},
24-
"/api/v2/files/wget/process": {},
25-
26-
"/api/v2/containers/search/log": {},
27-
}
28-
2922
func Proxy() gin.HandlerFunc {
3023
return func(c *gin.Context) {
3124
reqPath := c.Request.URL.Path
@@ -38,8 +31,8 @@ func Proxy() gin.HandlerFunc {
3831
return
3932
}
4033
var currentNode string
41-
if _, ok := wsUrl[reqPath]; ok {
42-
currentNode = c.Query("currentNode")
34+
if c.Query("operateNode") != "" {
35+
currentNode = c.Query("operateNode")
4336
} else {
4437
currentNode = c.Request.Header.Get("CurrentNode")
4538
}

core/utils/cmd/cmd.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package cmd
22

33
import (
4+
"bufio"
5+
"fmt"
6+
"io"
47
"os/exec"
58
"strings"
69
)
@@ -20,3 +23,36 @@ func Which(name string) bool {
2023
}
2124
return true
2225
}
26+
27+
func ExecWithStreamOutput(command string, outputCallback func(string)) error {
28+
cmd := exec.Command("bash", "-c", command)
29+
30+
stdout, err := cmd.StdoutPipe()
31+
if err != nil {
32+
return fmt.Errorf("failed to get stdout: %w", err)
33+
}
34+
35+
stderr, err := cmd.StderrPipe()
36+
if err != nil {
37+
return fmt.Errorf("failed to get stderr: %w", err)
38+
}
39+
40+
if err := cmd.Start(); err != nil {
41+
return fmt.Errorf("failed to start command: %w", err)
42+
}
43+
44+
go streamReader(stdout, outputCallback)
45+
go streamReader(stderr, outputCallback)
46+
47+
if err := cmd.Wait(); err != nil {
48+
return fmt.Errorf("command finished with error: %w", err)
49+
}
50+
return nil
51+
}
52+
53+
func streamReader(reader io.ReadCloser, callback func(string)) {
54+
scanner := bufio.NewScanner(reader)
55+
for scanner.Scan() {
56+
callback(scanner.Text())
57+
}
58+
}

core/utils/ssh/ssh.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,94 @@ func makePrivateKeySigner(privateKey []byte, passPhrase []byte) (gossh.Signer, e
9696
}
9797
return gossh.ParsePrivateKey(privateKey)
9898
}
99+
100+
func (c *SSHClient) RunWithStreamOutput(command string, outputCallback func(string)) error {
101+
session, err := c.Client.NewSession()
102+
if err != nil {
103+
return fmt.Errorf("failed to create SSH session: %w", err)
104+
}
105+
defer session.Close()
106+
107+
stdout, err := session.StdoutPipe()
108+
if err != nil {
109+
return fmt.Errorf("failed to set up stdout pipe: %w", err)
110+
}
111+
112+
stderr, err := session.StderrPipe()
113+
if err != nil {
114+
return fmt.Errorf("failed to set up stderr pipe: %w", err)
115+
}
116+
117+
if err := session.Start(command); err != nil {
118+
return fmt.Errorf("failed to start command: %w", err)
119+
}
120+
121+
stdoutCh := make(chan string, 100)
122+
stderrCh := make(chan string, 100)
123+
doneCh := make(chan struct{})
124+
125+
go func() {
126+
buffer := make([]byte, 1024)
127+
for {
128+
n, err := stdout.Read(buffer)
129+
if err != nil {
130+
close(stdoutCh)
131+
return
132+
}
133+
if n > 0 {
134+
stdoutCh <- string(buffer[:n])
135+
}
136+
}
137+
}()
138+
139+
go func() {
140+
buffer := make([]byte, 1024)
141+
for {
142+
n, err := stderr.Read(buffer)
143+
if err != nil {
144+
close(stderrCh)
145+
return
146+
}
147+
if n > 0 {
148+
stderrCh <- string(buffer[:n])
149+
}
150+
}
151+
}()
152+
153+
go func() {
154+
for {
155+
select {
156+
case stdoutOutput, ok := <-stdoutCh:
157+
if !ok {
158+
stdoutCh = nil
159+
if stderrCh == nil {
160+
close(doneCh)
161+
return
162+
}
163+
continue
164+
}
165+
if outputCallback != nil {
166+
outputCallback(stdoutOutput)
167+
}
168+
169+
case stderrOutput, ok := <-stderrCh:
170+
if !ok {
171+
stderrCh = nil
172+
if stdoutCh == nil {
173+
close(doneCh)
174+
return
175+
}
176+
continue
177+
}
178+
if outputCallback != nil {
179+
outputCallback(stderrOutput)
180+
}
181+
}
182+
}
183+
}()
184+
185+
err = session.Wait()
186+
<-doneCh
187+
188+
return err
189+
}

0 commit comments

Comments
 (0)