fonchain-fiee/pkg/utils/launch/launch.go
2025-02-19 14:24:15 +08:00

243 lines
5.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package launch
import (
"archive/zip"
"fmt"
"github.com/fonchain_enterprise/fonchain-main/pkg/request"
"io"
"log"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"sync"
"time"
)
// 下载文件并存储在指定文件夹
func downloadFile(url string, folder string, fileName string, wg *sync.WaitGroup, fileChan chan<- string, errChan chan<- error) {
defer wg.Done()
// 创建文件夹
err := os.MkdirAll(folder, os.ModePerm)
if err != nil {
errChan <- err
return
}
// 获取文件名
//fileName := filepath.Base(url)
filePath := filepath.Join(folder, fileName)
// 创建文件
out, err := os.Create(filePath)
if err != nil {
errChan <- err
return
}
defer out.Close()
// 下载文件
resp, err := http.Get(url)
if err != nil {
errChan <- err
return
}
defer resp.Body.Close()
// 写入文件
_, err = io.Copy(out, resp.Body)
if err != nil {
errChan <- err
return
}
fileChan <- filePath
}
// 将文件打包成ZIP
func zipFiles(zipFileName string, files map[string][]string) error {
newZipFile, err := os.Create(zipFileName)
if err != nil {
return err
}
defer newZipFile.Close()
zipWriter := zip.NewWriter(newZipFile)
for folder, fileList := range files {
for _, file := range fileList {
if err := addFileToZip(zipWriter, file, folder); err != nil {
return err
}
}
}
err = zipWriter.Close()
if err != nil {
return err
}
return nil
}
func addFileToZip(zipWriter *zip.Writer, filename string, folder string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
// 获取文件信息
info, err := file.Stat()
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
// 使用文件夹路径
header.Name = filepath.Join(folder, filepath.Base(filename))
//header.Name = filepath.Base(filename)
writer, err := zipWriter.CreateHeader(header)
if err != nil {
return err
}
_, err = io.Copy(writer, file)
return err
}
// 删除目录及其内容
func removeDir(dir string) error {
return os.RemoveAll(dir)
}
// 处理下载和压缩请求
func DownloadAndZip(reqData request.Response, fileType string, w http.ResponseWriter) {
// 标记是否只包含一个 attachment
isSingleAttachment := false
if len(reqData.Contracts) == 1 && len(reqData.Contracts[0].Attachment) == 1 {
isSingleAttachment = true
}
if isSingleAttachment {
// 只包含一个 contract且该 contract 只有一个 attachment则直接下载该文件
attachment := reqData.Contracts[0].Attachment[0]
if attachment.URL == "" {
http.Error(w, "URL not provided", http.StatusBadRequest)
return
}
// 下载文件
resp, err := http.Get(attachment.URL)
if err != nil {
http.Error(w, fmt.Sprintf("Failed to download file: %v", err), http.StatusInternalServerError)
return
}
defer resp.Body.Close()
// 设置响应头
w.Header().Set("Content-Type", resp.Header.Get("Content-Type"))
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", attachment.Name))
// 将文件内容发送给客户端
_, err = io.Copy(w, resp.Body)
if err != nil {
log.Printf("Failed to send file content: %v", err)
}
return
}
// 多个 URL则创建 ZIP 文件
tempDir := fmt.Sprintf("temp_%d", time.Now().UnixNano())
os.MkdirAll(tempDir, os.ModePerm)
filesToZip := make(map[string][]string)
var wg sync.WaitGroup
fileChan := make(chan string)
errChan := make(chan error)
//fileNameCount := make(map[string]int)
fileNameCount := make(map[string]map[string]int) // 存储每个附件下的文件名计数器
for _, contract := range reqData.Contracts {
contractFolder := contract.Theme
for _, attachment := range contract.Attachment {
wg.Add(1)
fileName := attachment.Name
ext := filepath.Ext(fileName)
name := strings.TrimSuffix(fileName, ext)
// 检查文件名是否重复,如果重复则对文件名进行枚举,否则不需要
if counts, ok := fileNameCount[contractFolder]; ok {
if count, exists := counts[fileName]; exists {
counts[fileName]++
fileName = fmt.Sprintf("%s(%d)%s", name, count, ext)
} else {
counts[fileName] = 1
}
} else {
fileNameCount[contractFolder] = map[string]int{fileName: 1}
}
go downloadFile(attachment.URL, tempDir, fileName, &wg, fileChan, errChan)
filesToZip[contractFolder] = append(filesToZip[contractFolder], filepath.Join(tempDir, fileName))
}
}
// Goroutine to handle file paths from fileChan
go func() {
for filePath := range fileChan {
log.Printf("Downloaded: %s", filePath)
}
}()
// Goroutine to handle errors from errChan
go func() {
for err := range errChan {
log.Printf("Error: %v", err)
}
}()
wg.Wait()
close(fileChan)
close(errChan)
// 创建ZIP文件
zipFileName := filepath.Join(tempDir, fileType+".zip")
err := zipFiles(zipFileName, filesToZip)
if err != nil {
log.Printf("Failed to create zip file: %v", err)
http.Error(w, "Failed to create zip file", http.StatusInternalServerError)
return
}
zipFile, err := os.Open(zipFileName)
if err != nil {
log.Printf("Failed to open zip file: %v", err)
http.Error(w, "Failed to open zip file", http.StatusInternalServerError)
return
}
// 返回ZIP文件
w.Header().Set("Content-Type", "application/zip")
encodedFileName := url.PathEscape(fmt.Sprintf("%s.zip", fileType))
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename*=UTF-8''%s", encodedFileName))
io.Copy(w, zipFile)
// 删除临时文件和目录
defer func() {
// 关闭文件句柄
if err := zipFile.Close(); err != nil {
log.Printf("Failed to close zip file: %v", err)
}
// 删除 ZIP 文件
if err := os.Remove(zipFileName); err != nil {
log.Printf("Failed to delete zip file: %v", err)
}
// 删除临时目录及其内容
if err := removeDir(tempDir); err != nil {
log.Printf("Failed to delete temp directory: %v", err)
}
}()
}