mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 08:20:25 +08:00 
			
		
		
		
	feat: 机器文件优化&sql新增引号包裹
This commit is contained in:
		@@ -266,6 +266,7 @@ const cellClick = (row: any, column: any, cell: any) => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const submitUpdateFields = () => {
 | 
			
		||||
    const dbInst = DbInst.getInst(state.dbId)
 | 
			
		||||
    let currentUpdatedFields = state.updatedFields;
 | 
			
		||||
    if (currentUpdatedFields.length <= 0) {
 | 
			
		||||
        return;
 | 
			
		||||
@@ -274,12 +275,12 @@ const submitUpdateFields = () => {
 | 
			
		||||
    let res = '';
 | 
			
		||||
    let divs: HTMLElement[] = [];
 | 
			
		||||
    currentUpdatedFields.forEach(a => {
 | 
			
		||||
        let sql = `UPDATE ${state.table} SET `;
 | 
			
		||||
        let sql = `UPDATE ${dbInst.wrapName(state.table)} SET `;
 | 
			
		||||
        let primaryKey = a.primaryKey;
 | 
			
		||||
        let primaryKeyType = a.primaryKeyType;
 | 
			
		||||
        let primaryKeyName = a.primaryKeyName;
 | 
			
		||||
        a.fields.forEach(f => {
 | 
			
		||||
            sql += ` ${f.fieldName} = ${DbInst.wrapColumnValue(f.fieldType, f.newValue)},`
 | 
			
		||||
            sql += ` ${dbInst.wrapName(f.fieldName)} = ${DbInst.wrapColumnValue(f.fieldType, f.newValue)},`
 | 
			
		||||
            // 如果修改的字段是主键
 | 
			
		||||
            if (f.fieldName === primaryKeyName) {
 | 
			
		||||
                primaryKey = f.oldValue
 | 
			
		||||
@@ -287,11 +288,11 @@ const submitUpdateFields = () => {
 | 
			
		||||
            divs.push(f.div)
 | 
			
		||||
        })
 | 
			
		||||
        sql = sql.substring(0, sql.length - 1)
 | 
			
		||||
        sql += ` WHERE ${primaryKeyName} = ${DbInst.wrapColumnValue(primaryKeyType, primaryKey)} ;`
 | 
			
		||||
        sql += ` WHERE ${dbInst.wrapName(primaryKeyName)} = ${DbInst.wrapColumnValue(primaryKeyType, primaryKey)} ;`
 | 
			
		||||
        res += sql;
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    DbInst.getInst(state.dbId).promptExeSql(db, res, () => { }, () => {
 | 
			
		||||
    dbInst.promptExeSql(db, res, () => { }, () => {
 | 
			
		||||
        currentUpdatedFields = [];
 | 
			
		||||
        divs.forEach(a => {
 | 
			
		||||
            a.classList.remove('update_field_active');
 | 
			
		||||
 
 | 
			
		||||
@@ -283,7 +283,7 @@ const selectData = async () => {
 | 
			
		||||
    const dbInst = state.ti.getNowDbInst();
 | 
			
		||||
    const { db } = state.ti;
 | 
			
		||||
    try {
 | 
			
		||||
        const countRes = await dbInst.runSql(db, DbInst.getDefaultCountSql(state.table, state.condition));
 | 
			
		||||
        const countRes = await dbInst.runSql(db, dbInst.getDefaultCountSql(state.table, state.condition));
 | 
			
		||||
        state.count = countRes.res[0].count;
 | 
			
		||||
        let sql = dbInst.getDefaultSelectSql(state.table, state.condition, state.orderBy, state.pageNum, state.pageSize);
 | 
			
		||||
        state.sql = sql;
 | 
			
		||||
@@ -427,6 +427,7 @@ const closeAddDataDialog = () => {
 | 
			
		||||
const addRow = async () => {
 | 
			
		||||
    dataForm.value.validate(async (valid: boolean) => {
 | 
			
		||||
        if (valid) {
 | 
			
		||||
            const dbInst = state.ti.getNowDbInst();
 | 
			
		||||
            const data = state.addDataDialog.data;
 | 
			
		||||
            // key: 字段名,value: 字段名提示
 | 
			
		||||
            let obj: any = {};
 | 
			
		||||
@@ -435,12 +436,12 @@ const addRow = async () => {
 | 
			
		||||
                if (!value) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                obj[`${item.columnName}`] = DbInst.wrapValueByType(value);
 | 
			
		||||
                obj[`${dbInst.wrapName(item.columnName)}`] = DbInst.wrapValueByType(value);
 | 
			
		||||
            }
 | 
			
		||||
            let columnNames = Object.keys(obj).join(',');
 | 
			
		||||
            let values = Object.values(obj).join(',');
 | 
			
		||||
            let sql = `INSERT INTO ${state.table} (${columnNames}) VALUES (${values});`;
 | 
			
		||||
            state.ti.getNowDbInst().promptExeSql(state.ti.db, sql, null, () => {
 | 
			
		||||
            let sql = `INSERT INTO ${dbInst.wrapName(state.table)} (${columnNames}) VALUES (${values});`;
 | 
			
		||||
            dbInst.promptExeSql(state.ti.db, sql, null, () => {
 | 
			
		||||
                closeAddDataDialog();
 | 
			
		||||
                onRefresh();
 | 
			
		||||
            });
 | 
			
		||||
 
 | 
			
		||||
@@ -141,9 +141,19 @@ export class DbInst {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取count sql
 | 
			
		||||
     * @param table 表名
 | 
			
		||||
     * @param condition 条件
 | 
			
		||||
     * @returns count sql
 | 
			
		||||
     */
 | 
			
		||||
    getDefaultCountSql = (table: string, condition?: string) => {
 | 
			
		||||
        return `SELECT COUNT(*) count FROM ${this.wrapName(table)} ${condition ? 'WHERE ' + condition : ''} limit 1`;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // 获取指定表的默认查询sql
 | 
			
		||||
    getDefaultSelectSql(table: string, condition: string, orderBy: string, pageNum: number, limit: number = DbInst.DefaultLimit) {
 | 
			
		||||
        const baseSql = `SELECT * FROM ${table} ${condition ? 'WHERE ' + condition : ''} ${orderBy ? orderBy : ''}`;
 | 
			
		||||
        const baseSql = `SELECT * FROM ${this.wrapName(table)} ${condition ? 'WHERE ' + condition : ''} ${orderBy ? orderBy : ''}`;
 | 
			
		||||
        if (this.type == 'mysql') {
 | 
			
		||||
            return `${baseSql} LIMIT ${(pageNum - 1) * limit}, ${limit};`;
 | 
			
		||||
        }
 | 
			
		||||
@@ -170,10 +180,10 @@ export class DbInst {
 | 
			
		||||
            let values = [];
 | 
			
		||||
            for (let column of columns) {
 | 
			
		||||
                const colName = column.columnName;
 | 
			
		||||
                colNames.push(colName);
 | 
			
		||||
                colNames.push(this.wrapName(colName));
 | 
			
		||||
                values.push(DbInst.wrapValueByType(data[colName]));
 | 
			
		||||
            }
 | 
			
		||||
            sqls.push(`INSERT INTO ${table} (${colNames.join(', ')}) VALUES(${values.join(', ')})`);
 | 
			
		||||
            sqls.push(`INSERT INTO ${this.wrapName(table)} (${colNames.join(', ')}) VALUES(${values.join(', ')})`);
 | 
			
		||||
        }
 | 
			
		||||
        return sqls.join(';\n') + ';';
 | 
			
		||||
    }
 | 
			
		||||
@@ -187,7 +197,7 @@ export class DbInst {
 | 
			
		||||
        const primaryKey = this.getDb(db).getColumn(table);
 | 
			
		||||
        const primaryKeyColumnName = primaryKey.columnName;
 | 
			
		||||
        const ids = datas.map((d: any) => `${DbInst.wrapColumnValue(primaryKey.columnType, d[primaryKeyColumnName])}`).join(',');
 | 
			
		||||
        return `DELETE FROM ${table} WHERE ${primaryKeyColumnName} IN (${ids})`;
 | 
			
		||||
        return `DELETE FROM ${this.wrapName(table)} WHERE ${this.wrapName(primaryKeyColumnName)} IN (${ids})`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
@@ -203,6 +213,22 @@ export class DbInst {
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 包裹数据库表名、字段名等,避免使用关键字为字段名或表名时报错
 | 
			
		||||
     * @param table
 | 
			
		||||
     * @param condition
 | 
			
		||||
     * @returns
 | 
			
		||||
     */
 | 
			
		||||
    wrapName = (name: string) => {
 | 
			
		||||
        if (this.type == 'mysql') {
 | 
			
		||||
            return `\`${name}\``;
 | 
			
		||||
        }
 | 
			
		||||
        if (this.type == 'postgres') {
 | 
			
		||||
            return `"${name}"`;
 | 
			
		||||
        }
 | 
			
		||||
        return name;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取或新建dbInst,如果缓存中不存在则新建,否则直接返回
 | 
			
		||||
     * @param inst 数据库实例,后端返回的列表接口中的信息
 | 
			
		||||
@@ -252,16 +278,6 @@ export class DbInst {
 | 
			
		||||
        dbInstCache.clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取count sql
 | 
			
		||||
     * @param table 表名
 | 
			
		||||
     * @param condition 条件
 | 
			
		||||
     * @returns count sql
 | 
			
		||||
     */
 | 
			
		||||
    static getDefaultCountSql = (table: string, condition?: string) => {
 | 
			
		||||
        return `SELECT COUNT(*) count FROM ${table} ${condition ? 'WHERE ' + condition : ''}`;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 根据返回值包装值,若值为字符串类型则添加''
 | 
			
		||||
     * @param val 值
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"mayfly-go/internal/machine/api/vo"
 | 
			
		||||
	"mayfly-go/internal/machine/application"
 | 
			
		||||
	"mayfly-go/internal/machine/domain/entity"
 | 
			
		||||
	"mayfly-go/internal/machine/infrastructure/machine"
 | 
			
		||||
	msgapp "mayfly-go/internal/msg/application"
 | 
			
		||||
	"mayfly-go/pkg/biz"
 | 
			
		||||
	"mayfly-go/pkg/ginx"
 | 
			
		||||
@@ -67,18 +68,19 @@ func (m *MachineFile) CreateFile(rc *req.Ctx) {
 | 
			
		||||
	form := ginx.BindJsonAndValid(g, new(form.MachineCreateFileForm))
 | 
			
		||||
	path := form.Path
 | 
			
		||||
 | 
			
		||||
	mi := m.MachineFileApp.GetMachine(fid)
 | 
			
		||||
 | 
			
		||||
	attrs := jsonx.Kvs("machine", mi, "path", path)
 | 
			
		||||
	rc.ReqParam = attrs
 | 
			
		||||
 | 
			
		||||
	attrs := jsonx.Kvs("path", path)
 | 
			
		||||
	var mi *machine.Info
 | 
			
		||||
	var err error
 | 
			
		||||
	if form.Type == dir {
 | 
			
		||||
		attrs["type"] = "目录"
 | 
			
		||||
		m.MachineFileApp.MkDir(fid, form.Path)
 | 
			
		||||
		mi, err = m.MachineFileApp.MkDir(fid, form.Path)
 | 
			
		||||
	} else {
 | 
			
		||||
		attrs["type"] = "文件"
 | 
			
		||||
		m.MachineFileApp.CreateFile(fid, form.Path)
 | 
			
		||||
		mi, err = m.MachineFileApp.CreateFile(fid, form.Path)
 | 
			
		||||
	}
 | 
			
		||||
	attrs["machine"] = mi
 | 
			
		||||
	rc.ReqParam = attrs
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "创建目录失败: %s")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineFile) ReadFileContent(rc *req.Ctx) {
 | 
			
		||||
@@ -87,7 +89,9 @@ func (m *MachineFile) ReadFileContent(rc *req.Ctx) {
 | 
			
		||||
	readPath := g.Query("path")
 | 
			
		||||
	readType := g.Query("type")
 | 
			
		||||
 | 
			
		||||
	sftpFile := m.MachineFileApp.ReadFile(fid, readPath)
 | 
			
		||||
	sftpFile, mi, err := m.MachineFileApp.ReadFile(fid, readPath)
 | 
			
		||||
	rc.ReqParam = jsonx.Kvs("machine", mi, "path", readPath)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "打开文件失败: %s")
 | 
			
		||||
	defer sftpFile.Close()
 | 
			
		||||
 | 
			
		||||
	fileInfo, _ := sftpFile.Stat()
 | 
			
		||||
@@ -96,9 +100,6 @@ func (m *MachineFile) ReadFileContent(rc *req.Ctx) {
 | 
			
		||||
	if readType != "1" {
 | 
			
		||||
		biz.IsTrue(filesize < max_read_size, "文件超过1m,请使用下载查看")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mi := m.MachineFileApp.GetMachine(fid)
 | 
			
		||||
	rc.ReqParam = jsonx.Kvs("machine", mi, "path", readPath, "filesize", filesize)
 | 
			
		||||
	// 如果读取类型为下载,则下载文件,否则获取文件内容
 | 
			
		||||
	if readType == "1" {
 | 
			
		||||
		// 截取文件名,如/usr/local/test.java -》 test.java
 | 
			
		||||
@@ -161,10 +162,9 @@ func (m *MachineFile) WriteFileContent(rc *req.Ctx) {
 | 
			
		||||
	ginx.BindJsonAndValid(g, form)
 | 
			
		||||
	path := form.Path
 | 
			
		||||
 | 
			
		||||
	mi := m.MachineFileApp.GetMachine(fid)
 | 
			
		||||
	mi, err := m.MachineFileApp.WriteFileContent(fid, path, []byte(form.Content))
 | 
			
		||||
	rc.ReqParam = jsonx.Kvs("machine", mi, "path", path)
 | 
			
		||||
 | 
			
		||||
	m.MachineFileApp.WriteFileContent(fid, path, []byte(form.Content))
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "打开文件失败: %s")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const MaxUploadFileSize int64 = 1024 * 1024 * 1024
 | 
			
		||||
@@ -181,9 +181,6 @@ func (m *MachineFile) UploadFile(rc *req.Ctx) {
 | 
			
		||||
	file, _ := fileheader.Open()
 | 
			
		||||
	defer file.Close()
 | 
			
		||||
 | 
			
		||||
	mi := m.MachineFileApp.GetMachine(fid)
 | 
			
		||||
	rc.ReqParam = jsonx.Kvs("machine", mi, "path", fmt.Sprintf("%s/%s", path, fileheader.Filename))
 | 
			
		||||
 | 
			
		||||
	la := rc.LoginAccount
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if err := recover(); err != nil {
 | 
			
		||||
@@ -195,7 +192,9 @@ func (m *MachineFile) UploadFile(rc *req.Ctx) {
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	m.MachineFileApp.UploadFile(fid, path, fileheader.Filename, file)
 | 
			
		||||
	mi, err := m.MachineFileApp.UploadFile(fid, path, fileheader.Filename, file)
 | 
			
		||||
	rc.ReqParam = jsonx.Kvs("machine", mi, "path", fmt.Sprintf("%s/%s", path, fileheader.Filename))
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "创建文件失败: %s")
 | 
			
		||||
	// 保存消息并发送文件上传成功通知
 | 
			
		||||
	m.MsgApp.CreateAndSend(la, ws.SuccessMsg("文件上传成功", fmt.Sprintf("[%s]文件已成功上传至 %s[%s:%s]", fileheader.Filename, mi.Name, mi.Ip, path)))
 | 
			
		||||
}
 | 
			
		||||
@@ -224,7 +223,9 @@ func (m *MachineFile) UploadFolder(rc *req.Ctx) {
 | 
			
		||||
	paths := mf.Value["paths"]
 | 
			
		||||
 | 
			
		||||
	folderName := filepath.Dir(paths[0])
 | 
			
		||||
	mi := m.MachineFileApp.GetMachine(fid)
 | 
			
		||||
	mcli := m.MachineFileApp.GetMachineCli(fid, basePath+"/"+folderName)
 | 
			
		||||
	mi := mcli.GetMachine()
 | 
			
		||||
	sftpCli := mcli.GetSftpCli()
 | 
			
		||||
	rc.ReqParam = jsonx.Kvs("machine", mi, "path", fmt.Sprintf("%s/%s", basePath, folderName))
 | 
			
		||||
 | 
			
		||||
	folderFiles := make([]FolderFile, len(paths))
 | 
			
		||||
@@ -234,7 +235,7 @@ func (m *MachineFile) UploadFolder(rc *req.Ctx) {
 | 
			
		||||
		dir := filepath.Dir(path)
 | 
			
		||||
		// 目录已建,则无需重复建
 | 
			
		||||
		if !mkdirs[dir] {
 | 
			
		||||
			m.MachineFileApp.MkDir(fid, basePath+"/"+dir)
 | 
			
		||||
			biz.ErrIsNilAppendErr(sftpCli.MkdirAll(basePath+"/"+dir), "创建目录失败: %s")
 | 
			
		||||
			mkdirs[dir] = true
 | 
			
		||||
		}
 | 
			
		||||
		folderFiles[i] = FolderFile{
 | 
			
		||||
@@ -244,7 +245,7 @@ func (m *MachineFile) UploadFolder(rc *req.Ctx) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 分组处理
 | 
			
		||||
	groupNum := 10
 | 
			
		||||
	groupNum := 30
 | 
			
		||||
	chunks := collx.ArraySplit(folderFiles, groupNum)
 | 
			
		||||
 | 
			
		||||
	var wg sync.WaitGroup
 | 
			
		||||
@@ -271,15 +272,19 @@ func (m *MachineFile) UploadFolder(rc *req.Ctx) {
 | 
			
		||||
				dir := file.Dir
 | 
			
		||||
				file, _ := fileHeader.Open()
 | 
			
		||||
				defer file.Close()
 | 
			
		||||
 | 
			
		||||
				logx.Debugf("上传文件夹: dir=%s -> filename=%s", dir, fileHeader.Filename)
 | 
			
		||||
				m.MachineFileApp.UploadFile(fid, basePath+"/"+dir, fileHeader.Filename, file)
 | 
			
		||||
 | 
			
		||||
				createfile, err := sftpCli.Create(fmt.Sprintf("%s/%s/%s", basePath, dir, fileHeader.Filename))
 | 
			
		||||
				biz.ErrIsNilAppendErr(err, "创建文件失败: %s")
 | 
			
		||||
				defer createfile.Close()
 | 
			
		||||
				io.Copy(createfile, file)
 | 
			
		||||
			}
 | 
			
		||||
		}(chunk, &wg)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 等待所有协程执行完成
 | 
			
		||||
	wg.Wait()
 | 
			
		||||
 | 
			
		||||
	// 保存消息并发送文件上传成功通知
 | 
			
		||||
	m.MsgApp.CreateAndSend(rc.LoginAccount, ws.SuccessMsg("文件上传成功", fmt.Sprintf("[%s]文件夹已成功上传至 %s[%s:%s]", folderName, mi.Name, mi.Ip, basePath)))
 | 
			
		||||
}
 | 
			
		||||
@@ -291,10 +296,9 @@ func (m *MachineFile) RemoveFile(rc *req.Ctx) {
 | 
			
		||||
	rmForm := new(form.MachineFileOpForm)
 | 
			
		||||
	ginx.BindJsonAndValid(g, rmForm)
 | 
			
		||||
 | 
			
		||||
	mi := m.MachineFileApp.GetMachine(fid)
 | 
			
		||||
	mi, err := m.MachineFileApp.RemoveFile(fid, rmForm.Path...)
 | 
			
		||||
	rc.ReqParam = jsonx.Kvs("machine", mi, "path", rmForm.Path)
 | 
			
		||||
 | 
			
		||||
	m.MachineFileApp.RemoveFile(fid, rmForm.Path...)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "删除文件失败: %s")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineFile) CopyFile(rc *req.Ctx) {
 | 
			
		||||
@@ -303,7 +307,8 @@ func (m *MachineFile) CopyFile(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
	cpForm := new(form.MachineFileOpForm)
 | 
			
		||||
	ginx.BindJsonAndValid(g, cpForm)
 | 
			
		||||
	mi := m.MachineFileApp.Copy(fid, cpForm.ToPath, cpForm.Path...)
 | 
			
		||||
	mi, err := m.MachineFileApp.Copy(fid, cpForm.ToPath, cpForm.Path...)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "文件拷贝失败: %s")
 | 
			
		||||
	rc.ReqParam = jsonx.Kvs("machine", mi, "cp", cpForm)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -313,8 +318,9 @@ func (m *MachineFile) MvFile(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
	cpForm := new(form.MachineFileOpForm)
 | 
			
		||||
	ginx.BindJsonAndValid(g, cpForm)
 | 
			
		||||
	mi := m.MachineFileApp.Mv(fid, cpForm.ToPath, cpForm.Path...)
 | 
			
		||||
	mi, err := m.MachineFileApp.Mv(fid, cpForm.ToPath, cpForm.Path...)
 | 
			
		||||
	rc.ReqParam = jsonx.Kvs("machine", mi, "mv", cpForm)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "文件移动失败: %s")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineFile) Rename(rc *req.Ctx) {
 | 
			
		||||
@@ -323,10 +329,9 @@ func (m *MachineFile) Rename(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
	rename := new(form.MachineFileRename)
 | 
			
		||||
	ginx.BindJsonAndValid(g, rename)
 | 
			
		||||
	biz.ErrIsNilAppendErr(m.MachineFileApp.Rename(fid, rename.Oldname, rename.Newname), "文件重命名失败: %s")
 | 
			
		||||
 | 
			
		||||
	mi := m.MachineFileApp.GetMachine(fid)
 | 
			
		||||
	mi, err := m.MachineFileApp.Rename(fid, rename.Oldname, rename.Newname)
 | 
			
		||||
	rc.ReqParam = jsonx.Kvs("machine", mi, "rename", rename)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "文件重命名失败: %s")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getFileType(fm fs.FileMode) string {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package application
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/fs"
 | 
			
		||||
@@ -31,15 +32,18 @@ type MachineFile interface {
 | 
			
		||||
	Delete(id uint64)
 | 
			
		||||
 | 
			
		||||
	// 获取文件关联的机器信息,主要用于记录日志使用
 | 
			
		||||
	GetMachine(fileId uint64) *machine.Info
 | 
			
		||||
	// GetMachine(fileId uint64) *machine.Info
 | 
			
		||||
 | 
			
		||||
	// 检查文件路径,并返回机器id
 | 
			
		||||
	GetMachineCli(fileId uint64, path ...string) *machine.Cli
 | 
			
		||||
 | 
			
		||||
	/**  sftp 相关操作 **/
 | 
			
		||||
 | 
			
		||||
	// 创建目录
 | 
			
		||||
	MkDir(fid uint64, path string)
 | 
			
		||||
	MkDir(fid uint64, path string) (*machine.Info, error)
 | 
			
		||||
 | 
			
		||||
	// 创建文件
 | 
			
		||||
	CreateFile(fid uint64, path string)
 | 
			
		||||
	CreateFile(fid uint64, path string) (*machine.Info, error)
 | 
			
		||||
 | 
			
		||||
	// 读取目录
 | 
			
		||||
	ReadDir(fid uint64, path string) []fs.FileInfo
 | 
			
		||||
@@ -51,22 +55,22 @@ type MachineFile interface {
 | 
			
		||||
	FileStat(fid uint64, path string) string
 | 
			
		||||
 | 
			
		||||
	// 读取文件内容
 | 
			
		||||
	ReadFile(fileId uint64, path string) *sftp.File
 | 
			
		||||
	ReadFile(fileId uint64, path string) (*sftp.File, *machine.Info, error)
 | 
			
		||||
 | 
			
		||||
	// 写文件
 | 
			
		||||
	WriteFileContent(fileId uint64, path string, content []byte)
 | 
			
		||||
	WriteFileContent(fileId uint64, path string, content []byte) (*machine.Info, error)
 | 
			
		||||
 | 
			
		||||
	// 文件上传
 | 
			
		||||
	UploadFile(fileId uint64, path, filename string, reader io.Reader)
 | 
			
		||||
	UploadFile(fileId uint64, path, filename string, reader io.Reader) (*machine.Info, error)
 | 
			
		||||
 | 
			
		||||
	// 移除文件
 | 
			
		||||
	RemoveFile(fileId uint64, path ...string)
 | 
			
		||||
	RemoveFile(fileId uint64, path ...string) (*machine.Info, error)
 | 
			
		||||
 | 
			
		||||
	Copy(fileId uint64, toPath string, paths ...string) *machine.Info
 | 
			
		||||
	Copy(fileId uint64, toPath string, paths ...string) (*machine.Info, error)
 | 
			
		||||
 | 
			
		||||
	Mv(fileId uint64, toPath string, paths ...string) *machine.Info
 | 
			
		||||
	Mv(fileId uint64, toPath string, paths ...string) (*machine.Info, error)
 | 
			
		||||
 | 
			
		||||
	Rename(fileId uint64, oldname string, newname string) error
 | 
			
		||||
	Rename(fileId uint64, oldname string, newname string) (*machine.Info, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newMachineFileApp(machineFileRepo repository.MachineFile, machineRepo repository.Machine) MachineFile {
 | 
			
		||||
@@ -111,20 +115,19 @@ func (m *machineFileAppImpl) Delete(id uint64) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineFileAppImpl) ReadDir(fid uint64, path string) []fs.FileInfo {
 | 
			
		||||
	machineId := m.checkAndReturnMid(fid, path)
 | 
			
		||||
	mcli := m.GetMachineCli(fid, path)
 | 
			
		||||
	if !strings.HasSuffix(path, "/") {
 | 
			
		||||
		path = path + "/"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sftpCli := m.getSftpCli(machineId)
 | 
			
		||||
	fis, err := sftpCli.ReadDir(path)
 | 
			
		||||
	fis, err := mcli.GetSftpCli().ReadDir(path)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "读取目录失败: %s")
 | 
			
		||||
	return fis
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineFileAppImpl) GetDirSize(fid uint64, path string) string {
 | 
			
		||||
	machineId := m.checkAndReturnMid(fid, path)
 | 
			
		||||
	res, err := GetMachineApp().GetCli(machineId).Run(fmt.Sprintf("du -sh %s", path))
 | 
			
		||||
	mcli := m.GetMachineCli(fid, path)
 | 
			
		||||
	res, err := mcli.Run(fmt.Sprintf("du -sh %s", path))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// 若存在目录为空,则可能会返回如下内容。最后一行即为真正目录内容所占磁盘空间大小
 | 
			
		||||
		//du: cannot access ‘/proc/19087/fd/3’: No such file or directory\n
 | 
			
		||||
@@ -145,121 +148,116 @@ func (m *machineFileAppImpl) GetDirSize(fid uint64, path string) string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineFileAppImpl) FileStat(fid uint64, path string) string {
 | 
			
		||||
	machineId := m.checkAndReturnMid(fid, path)
 | 
			
		||||
	res, err := GetMachineApp().GetCli(machineId).Run(fmt.Sprintf("stat -L %s", path))
 | 
			
		||||
	mcli := m.GetMachineCli(fid, path)
 | 
			
		||||
	res, err := mcli.Run(fmt.Sprintf("stat -L %s", path))
 | 
			
		||||
	biz.ErrIsNil(err, res)
 | 
			
		||||
	return res
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineFileAppImpl) MkDir(fid uint64, path string) {
 | 
			
		||||
	machineId := m.checkAndReturnMid(fid, path)
 | 
			
		||||
func (m *machineFileAppImpl) MkDir(fid uint64, path string) (*machine.Info, error) {
 | 
			
		||||
	mcli := m.GetMachineCli(fid, path)
 | 
			
		||||
	if !strings.HasSuffix(path, "/") {
 | 
			
		||||
		path = path + "/"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sftpCli := m.getSftpCli(machineId)
 | 
			
		||||
	err := sftpCli.MkdirAll(path)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "创建目录失败: %s")
 | 
			
		||||
	err := mcli.GetSftpCli().MkdirAll(path)
 | 
			
		||||
	return mcli.GetMachine(), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineFileAppImpl) CreateFile(fid uint64, path string) {
 | 
			
		||||
	machineId := m.checkAndReturnMid(fid, path)
 | 
			
		||||
	sftpCli := m.getSftpCli(machineId)
 | 
			
		||||
	file, err := sftpCli.Create(path)
 | 
			
		||||
func (m *machineFileAppImpl) CreateFile(fid uint64, path string) (*machine.Info, error) {
 | 
			
		||||
	mcli := m.GetMachineCli(fid, path)
 | 
			
		||||
	file, err := mcli.GetSftpCli().Create(path)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "创建文件失败: %s")
 | 
			
		||||
	defer file.Close()
 | 
			
		||||
	return mcli.GetMachine(), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineFileAppImpl) ReadFile(fileId uint64, path string) *sftp.File {
 | 
			
		||||
	machineId := m.checkAndReturnMid(fileId, path)
 | 
			
		||||
	sftpCli := m.getSftpCli(machineId)
 | 
			
		||||
func (m *machineFileAppImpl) ReadFile(fileId uint64, path string) (*sftp.File, *machine.Info, error) {
 | 
			
		||||
	mcli := m.GetMachineCli(fileId, path)
 | 
			
		||||
	// 读取文件内容
 | 
			
		||||
	fc, err := sftpCli.Open(path)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "打开文件失败: %s")
 | 
			
		||||
	return fc
 | 
			
		||||
	fc, err := mcli.GetSftpCli().Open(path)
 | 
			
		||||
	return fc, mcli.GetMachine(), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 写文件内容
 | 
			
		||||
func (m *machineFileAppImpl) WriteFileContent(fileId uint64, path string, content []byte) {
 | 
			
		||||
	machineId := m.checkAndReturnMid(fileId, path)
 | 
			
		||||
 | 
			
		||||
	sftpCli := m.getSftpCli(machineId)
 | 
			
		||||
	f, err := sftpCli.OpenFile(path, os.O_WRONLY|os.O_TRUNC|os.O_CREATE|os.O_RDWR)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "打开文件失败: %s")
 | 
			
		||||
func (m *machineFileAppImpl) WriteFileContent(fileId uint64, path string, content []byte) (*machine.Info, error) {
 | 
			
		||||
	mcli := m.GetMachineCli(fileId, path)
 | 
			
		||||
	mi := mcli.GetMachine()
 | 
			
		||||
	f, err := mcli.GetSftpCli().OpenFile(path, os.O_WRONLY|os.O_TRUNC|os.O_CREATE|os.O_RDWR)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return mi, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	fi, _ := f.Stat()
 | 
			
		||||
	biz.IsTrue(!fi.IsDir(), "该路径不是文件")
 | 
			
		||||
	f.Write(content)
 | 
			
		||||
	return mi, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 上传文件
 | 
			
		||||
func (m *machineFileAppImpl) UploadFile(fileId uint64, path, filename string, reader io.Reader) {
 | 
			
		||||
	machineId := m.checkAndReturnMid(fileId, path)
 | 
			
		||||
func (m *machineFileAppImpl) UploadFile(fileId uint64, path, filename string, reader io.Reader) (*machine.Info, error) {
 | 
			
		||||
	mcli := m.GetMachineCli(fileId, path)
 | 
			
		||||
	mi := mcli.GetMachine()
 | 
			
		||||
	if !strings.HasSuffix(path, "/") {
 | 
			
		||||
		path = path + "/"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sftpCli := m.getSftpCli(machineId)
 | 
			
		||||
	createfile, err := sftpCli.Create(path + filename)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "创建文件失败: %s")
 | 
			
		||||
	createfile, err := mcli.GetSftpCli().Create(path + filename)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return mi, err
 | 
			
		||||
	}
 | 
			
		||||
	defer createfile.Close()
 | 
			
		||||
 | 
			
		||||
	io.Copy(createfile, reader)
 | 
			
		||||
	return mi, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 删除文件
 | 
			
		||||
func (m *machineFileAppImpl) RemoveFile(fileId uint64, path ...string) {
 | 
			
		||||
	machineId := m.checkAndReturnMid(fileId, path...)
 | 
			
		||||
func (m *machineFileAppImpl) RemoveFile(fileId uint64, path ...string) (*machine.Info, error) {
 | 
			
		||||
	mcli := m.GetMachineCli(fileId, path...)
 | 
			
		||||
	minfo := mcli.GetMachine()
 | 
			
		||||
 | 
			
		||||
	// 优先使用命令删除(速度快),sftp需要递归遍历删除子文件等
 | 
			
		||||
	mcli := GetMachineApp().GetCli(machineId)
 | 
			
		||||
	res, err := mcli.Run(fmt.Sprintf("rm -rf %s", strings.Join(path, " ")))
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return
 | 
			
		||||
		return minfo, nil
 | 
			
		||||
	}
 | 
			
		||||
	logx.Errorf("使用命令rm删除文件失败: %s", res)
 | 
			
		||||
 | 
			
		||||
	sftpCli := m.getSftpCli(machineId)
 | 
			
		||||
	sftpCli := mcli.GetSftpCli()
 | 
			
		||||
	for _, p := range path {
 | 
			
		||||
		err := sftpCli.RemoveAll(p)
 | 
			
		||||
		biz.ErrIsNilAppendErr(err, "删除文件失败: %s")
 | 
			
		||||
		err = sftpCli.RemoveAll(p)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return minfo, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineFileAppImpl) Copy(fileId uint64, toPath string, paths ...string) *machine.Info {
 | 
			
		||||
	mid := m.checkAndReturnMid(fileId, paths...)
 | 
			
		||||
	mcli := GetMachineApp().GetCli(mid)
 | 
			
		||||
func (m *machineFileAppImpl) Copy(fileId uint64, toPath string, paths ...string) (*machine.Info, error) {
 | 
			
		||||
	mcli := m.GetMachineCli(fileId, paths...)
 | 
			
		||||
	mi := mcli.GetMachine()
 | 
			
		||||
	res, err := mcli.Run(fmt.Sprintf("cp -r %s %s", strings.Join(paths, " "), toPath))
 | 
			
		||||
	biz.ErrIsNil(err, "文件拷贝失败: %s", res)
 | 
			
		||||
	return mcli.GetMachine()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return mi, errors.New(res)
 | 
			
		||||
	}
 | 
			
		||||
	return mi, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineFileAppImpl) Mv(fileId uint64, toPath string, paths ...string) *machine.Info {
 | 
			
		||||
	mid := m.checkAndReturnMid(fileId, paths...)
 | 
			
		||||
	mcli := GetMachineApp().GetCli(mid)
 | 
			
		||||
func (m *machineFileAppImpl) Mv(fileId uint64, toPath string, paths ...string) (*machine.Info, error) {
 | 
			
		||||
	mcli := m.GetMachineCli(fileId, paths...)
 | 
			
		||||
	mi := mcli.GetMachine()
 | 
			
		||||
	res, err := mcli.Run(fmt.Sprintf("mv %s %s", strings.Join(paths, " "), toPath))
 | 
			
		||||
	biz.ErrIsNil(err, "文件移动失败: %s", res)
 | 
			
		||||
	return mcli.GetMachine()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return mi, errors.New(res)
 | 
			
		||||
	}
 | 
			
		||||
	return mi, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineFileAppImpl) Rename(fileId uint64, oldname string, newname string) error {
 | 
			
		||||
	mid := m.checkAndReturnMid(fileId, newname)
 | 
			
		||||
	sftpCli := m.getSftpCli(mid)
 | 
			
		||||
	return sftpCli.Rename(oldname, newname)
 | 
			
		||||
func (m *machineFileAppImpl) Rename(fileId uint64, oldname string, newname string) (*machine.Info, error) {
 | 
			
		||||
	mcli := m.GetMachineCli(fileId, newname)
 | 
			
		||||
	return mcli.GetMachine(), mcli.GetSftpCli().Rename(oldname, newname)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 获取sftp client
 | 
			
		||||
func (m *machineFileAppImpl) getSftpCli(machineId uint64) *sftp.Client {
 | 
			
		||||
	return GetMachineApp().GetCli(machineId).GetSftpCli()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineFileAppImpl) GetMachine(fileId uint64) *machine.Info {
 | 
			
		||||
	return GetMachineApp().GetCli(m.GetById(fileId).MachineId).GetMachine()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 校验并返回实际可访问的文件path
 | 
			
		||||
func (m *machineFileAppImpl) checkAndReturnMid(fid uint64, inputPath ...string) uint64 {
 | 
			
		||||
// 获取文件机器cli
 | 
			
		||||
func (m *machineFileAppImpl) GetMachineCli(fid uint64, inputPath ...string) *machine.Cli {
 | 
			
		||||
	biz.IsTrue(fid != 0, "文件id不能为空")
 | 
			
		||||
	mf := m.GetById(fid)
 | 
			
		||||
	biz.NotNil(mf, "文件不存在")
 | 
			
		||||
@@ -267,5 +265,5 @@ func (m *machineFileAppImpl) checkAndReturnMid(fid uint64, inputPath ...string)
 | 
			
		||||
		// 接口传入的地址需为配置路径的子路径
 | 
			
		||||
		biz.IsTrue(strings.HasPrefix(path, mf.Path), "无权访问该目录或文件: %s", path)
 | 
			
		||||
	}
 | 
			
		||||
	return mf.MachineId
 | 
			
		||||
	return GetMachineApp().GetCli(mf.MachineId)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user