package file_export import ( "encoding/json" "net/http" "os" "path" "path/filepath" "be.ems/lib/file" "be.ems/lib/log" "be.ems/lib/services" "be.ems/src/framework/config" "be.ems/src/framework/datasource" "be.ems/src/framework/i18n" "be.ems/src/framework/ssh" "be.ems/src/framework/utils/crypto" "be.ems/src/framework/utils/ctx" "be.ems/src/framework/vo/result" systemService "be.ems/src/modules/system/service" "github.com/gin-gonic/gin" ) type SysJobResponse struct { SysJob TableName string `json:"tableName"` TableDisplay string `json:"tableDisplay"` FilePath string `json:"filePath"` } type TargetParams struct { Duration int `json:"duration"` TableName string `json:"tableName"` Columns string `json:"columns"` // exported column name of time string TimeCol string `json:"timeCol"` // time stamp of column name TimeUnit string `json:"timeUnit"` // timestamp unit: second/micro/milli Extras string `json:"extras"` // extras condition for where FilePath string `json:"filePath"` // file path } func (m *SysJob) GetFileExportTable(c *gin.Context) { var results []SysJob err := datasource.DefaultDB().Table(m.TableName()).Where("invoke_target=? and status=1", INVOKE_FILE_EXPORT). Find(&results).Error if err != nil { c.JSON(http.StatusOK, services.ErrResp(err.Error())) return } language := ctx.AcceptLanguage(c) var response []SysJobResponse for _, job := range results { var params TargetParams if err := json.Unmarshal([]byte(job.TargetParams), ¶ms); err != nil { c.JSON(http.StatusOK, services.ErrResp(err.Error())) return } TableDisplay := i18n.TKey(language, "table."+params.TableName) if TableDisplay == "" { TableDisplay = params.TableName } response = append(response, SysJobResponse{ SysJob: job, TableName: params.TableName, TableDisplay: TableDisplay, FilePath: params.FilePath, }) } c.JSON(http.StatusOK, services.DataResp(response)) } func (m *FileExport) GetFileList(c *gin.Context) { var querys FileExportQuery if err := c.ShouldBindQuery(&querys); err != nil { c.JSON(http.StatusOK, services.ErrResp(err.Error())) return } files, err := file.GetFileInfo(querys.Path, querys.Suffix) if err != nil { log.Error("failed to GetFileInfo:", err) c.JSON(http.StatusOK, services.ErrResp(err.Error())) return } // split files list lenNum := int64(len(files)) start := (querys.PageNum - 1) * querys.PageSize end := start + querys.PageSize var splitList []file.FileInfo if start >= lenNum { splitList = []file.FileInfo{} } else if end >= lenNum { splitList = files[start:] } else { splitList = files[start:end] } total := len(files) c.JSON(http.StatusOK, services.TotalDataResp(splitList, total)) } func (m *FileExport) Total(c *gin.Context) { dir := c.Query("path") fileCount, dirCount, err := file.GetFileAndDirCount(dir) if err != nil { log.Error("failed to GetFileAndDirCount:", err) c.JSON(http.StatusOK, services.ErrResp(err.Error())) return } total := fileCount + dirCount c.JSON(http.StatusOK, services.TotalResp(int64(total))) } func (m *FileExport) DownloadHandler(c *gin.Context) { dir := c.Query("path") fileName := c.Param("fileName") filePath := filepath.Join(dir, fileName) file, err := os.Open(filePath) if err != nil { c.JSON(http.StatusOK, services.ErrResp(err.Error())) return } defer file.Close() if _, err := os.Stat(filePath); os.IsNotExist(err) { c.JSON(http.StatusOK, services.ErrResp(err.Error())) return } c.Header("Content-Disposition", "attachment; filename="+fileName) c.Header("Content-Type", "application/octet-stream") c.File(filePath) } func (m *FileExport) Delete(c *gin.Context) { fileName := c.Param("fileName") dir := c.Query("path") filePath := filepath.Join(dir, fileName) if err := os.Remove(filePath); err != nil { c.JSON(http.StatusOK, services.ErrResp(err.Error())) return } c.JSON(http.StatusNoContent, nil) // 204 No Content } // 设置FTP配置 // POST /table/ftp func (m *SysJob) SetFTPConfig(c *gin.Context) { language := ctx.AcceptLanguage(c) var body struct { Password string `json:"password" ` Username string `json:"username" binding:"required"` ToIp string `json:"toIp" binding:"required"` ToPort int64 `json:"toPort" binding:"required"` Enable bool `json:"enable"` Dir string `json:"dir" binding:"required"` } if err := c.ShouldBindBodyWithJSON(&body); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } // 获取配置 cfg := systemService.NewSysConfigImpl.SelectConfigByKey("sys.exportTable") if cfg.ConfigID != "" { // 加密body appKey := config.Get("aes.appKey").(string) byteData, err := json.Marshal(body) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } bodyEn, err := crypto.AESEncryptBase64(string(byteData), appKey) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } // 更新 cfg.ConfigValue = bodyEn systemService.NewSysConfigImpl.UpdateConfig(cfg) } c.JSON(200, result.Ok(nil)) } // 获取FTP配置 // GET /table/ftp func (m *SysJob) GetFTPConfig(c *gin.Context) { // 获取配置 cfg := systemService.NewSysConfigImpl.SelectConfigByKey("sys.exportTable") if cfg.ConfigID != "" { // 解密body appKey := config.Get("aes.appKey").(string) bodyDe, err := crypto.AESDecryptBase64(cfg.ConfigValue, appKey) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } var body struct { Password string `json:"password" ` Username string `json:"username" binding:"required"` ToIp string `json:"toIp" binding:"required"` ToPort int64 `json:"toPort" binding:"required"` Enable bool `json:"enable"` Dir string `json:"dir" binding:"required"` } err = json.Unmarshal([]byte(bodyDe), &body) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } c.JSON(200, result.OkData(body)) return } c.JSON(200, result.Ok(nil)) } // FTP发送 // PUT /table/ftp func (m *SysJob) PutFTP(c *gin.Context) { language := ctx.AcceptLanguage(c) var body struct { FilePath string `json:"filePath" binding:"required"` FileName string `json:"fileName" binding:"required"` } if err := c.ShouldBindBodyWithJSON(&body); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } localFilePath := filepath.Join(body.FilePath, body.FileName) // 判断文件是否存在 if _, err := os.Stat(localFilePath); os.IsNotExist(err) { c.JSON(200, result.ErrMsg(err.Error())) return } // 获取配置 var cfgData struct { Password string `json:"password" ` Username string `json:"username" binding:"required"` ToIp string `json:"toIp" binding:"required"` ToPort int64 `json:"toPort" binding:"required"` Enable bool `json:"enable"` Dir string `json:"dir" binding:"required"` } cfg := systemService.NewSysConfigImpl.SelectConfigByKey("sys.exportTable") if cfg.ConfigID != "" { // 解密body appKey := config.Get("aes.appKey").(string) bodyDe, err := crypto.AESDecryptBase64(cfg.ConfigValue, appKey) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } err = json.Unmarshal([]byte(bodyDe), &cfgData) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } } if !cfgData.Enable { c.JSON(200, result.ErrMsg("Setting Remote Backup is disabled")) return } connSSH := ssh.ConnSSH{ User: cfgData.Username, Password: cfgData.Password, Addr: cfgData.ToIp, Port: cfgData.ToPort, AuthMode: "0", } sshClient, err := connSSH.NewClient() if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } defer sshClient.Close() // 网元主机的SSH客户端进行文件传输 sftpClient, err := sshClient.NewClientSFTP() if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } defer sftpClient.Close() // 远程文件 remotePath := filepath.Join(cfgData.Dir, path.Base(body.FilePath), body.FileName) // 复制到远程 if err = sftpClient.CopyFileLocalToRemote(localFilePath, remotePath); err != nil { c.JSON(200, result.ErrMsg("error uploading file")) return } c.JSON(200, result.Ok(nil)) }