You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
211 lines
5.1 KiB
211 lines
5.1 KiB
package core
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io"
|
|
"net/rpc"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"scagent/config"
|
|
"scagent/util"
|
|
"strings"
|
|
"time"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// 压缩文件
|
|
type ZipBlock struct {
|
|
Basepath string
|
|
Curpath string // 当前路径
|
|
SelFile []string // 选中的文件
|
|
RemoteAddr string // 远程主机地址,带端口
|
|
RemotePath string // 远程主机的存储路径
|
|
}
|
|
|
|
// FileTransferService 定义文件传输服务
|
|
type FileService struct{}
|
|
|
|
// FileInfo 包含文件的元信息
|
|
type FileInfo struct {
|
|
FileName string
|
|
FileSize int64
|
|
}
|
|
|
|
// FileChunk 表示文件的一部分
|
|
type FileChunk struct {
|
|
Data []byte
|
|
FileName string
|
|
Offset int64
|
|
IsLast bool
|
|
}
|
|
|
|
// SendFile 接收文件信息(名称和大小)
|
|
func (f *FileService) SendFileInfo(info FileInfo, reply *bool) error {
|
|
// 创建保存文件的目录
|
|
if err := os.MkdirAll("received_files", 0755); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 创建文件(如果存在则截断)
|
|
filePath := filepath.Join("received_files", info.FileName)
|
|
file, err := os.Create(filePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
*reply = true
|
|
return nil
|
|
}
|
|
|
|
// SendFileChunk 接收文件块并写入文件
|
|
func (f *FileService) SendFileChunk(chunk FileChunk, reply *bool) error {
|
|
filePath := filepath.Join("received_files", chunk.FileName)
|
|
|
|
// 打开文件,使用追加模式
|
|
file, err := os.OpenFile(filePath, os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
// 移动到指定偏移量
|
|
if _, err := file.Seek(chunk.Offset, io.SeekStart); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 写入数据
|
|
if _, err := file.Write(chunk.Data); err != nil {
|
|
return err
|
|
}
|
|
|
|
*reply = true
|
|
return nil
|
|
}
|
|
|
|
// 压缩文件
|
|
// 返回压缩包的名称
|
|
func (f *FileService) Compress(args *ZipBlock, reply *string) error {
|
|
// fmt.Printf("compress args: %v\n", args)
|
|
// 启用日志
|
|
logger := util.NewProductionLogger()
|
|
defer logger.Sync()
|
|
// 实际路径
|
|
realFilePath := filepath.Join(args.Basepath, args.Curpath)
|
|
logger.Info("Compress", zap.String("realFilePath", realFilePath))
|
|
// zip 文件名
|
|
zpFileName := "BIU_" + time.Now().Format("20060102_150405") + ".zip"
|
|
// 创建zip 异步?
|
|
taskId := make(chan string)
|
|
// 异步压缩
|
|
go func() {
|
|
util.CompressToZip(zpFileName, realFilePath, args.SelFile)
|
|
taskId <- "arcok"
|
|
// 日志输出
|
|
logger.Info("压缩文件", zap.String("filename", zpFileName), zap.String("path", realFilePath))
|
|
}()
|
|
// ZIP 文件的实际路径
|
|
ziprl := path.Join(config.G.FilePath, "/sync_zips", zpFileName)
|
|
// zip 创建成功后
|
|
rest := <-taskId
|
|
// 如果压缩包生成成功以后再执行
|
|
if strings.EqualFold(strings.ToLower(rest), "arcok") {
|
|
// 合并为实际路径
|
|
// remotePath := path.Join("/www/wwwroot", args.RemotePath, zpFileName)
|
|
// 异步发送文件到远程服务器上
|
|
// go clientUploadFile(args.RemoteAddr, ziprl, remotePath)
|
|
go clientUploadFile(args.RemoteAddr, ziprl)
|
|
|
|
// 返回压缩包名称
|
|
*reply = ziprl
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// 客户端调用RPC传送文件的函数
|
|
// 传入zip的实际路径,远程的服务器带端口,远程文件存放路径
|
|
func clientUploadFile(remote string, filePath string) error {
|
|
// fmt.Printf("remote: %s, filePath: %s, uploadPath: %s\n", remote, filePath, uploadPath)
|
|
// 启用日志
|
|
logger := util.NewProductionLogger()
|
|
defer logger.Sync()
|
|
// 将服务器的信息拆分为ip和端口
|
|
harr := strings.Split(remote, ":")
|
|
dstip := harr[0]
|
|
dport := harr[1]
|
|
|
|
// 连接到RPC服务器
|
|
service := fmt.Sprintf("%v:%v", dstip, dport)
|
|
client, err := rpc.Dial("tcp", service)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer client.Close()
|
|
// 获取文件信息
|
|
fileInfo, err := os.Stat(filePath)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// 提取文件名
|
|
fileName := filepath.Base(filePath)
|
|
// 发送文件信息
|
|
var reply bool
|
|
err = client.Call("FileService.SendFileInfo", FileInfo{
|
|
FileName: fileName,
|
|
FileSize: fileInfo.Size(),
|
|
}, &reply)
|
|
if err != nil || !reply {
|
|
logger.Error("发送文件信息失败", zap.Error(err))
|
|
}
|
|
// 打开文件准备读取
|
|
file, err := os.Open(filePath)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer file.Close()
|
|
|
|
// 读取并发送文件块
|
|
buffer := make([]byte, 4096) // 4KB块大小
|
|
reader := bufio.NewReader(file)
|
|
var offset int64 = 0
|
|
|
|
// logger.Info("开始发送文件: %s (大小: %d bytes)", zap.String("filename", fileName), zap.String("path", filePath))
|
|
fmt.Printf("开始发送文件: %s (大小: %d bytes)\n", fileName, fileInfo.Size())
|
|
|
|
// 发送文件
|
|
for {
|
|
n, err := reader.Read(buffer)
|
|
if err != nil {
|
|
break
|
|
}
|
|
|
|
// 判断是否是最后一块
|
|
isLast := offset+int64(n) >= fileInfo.Size()
|
|
|
|
// 发送文件块
|
|
err = client.Call("FileService.SendFileChunk", FileChunk{
|
|
Data: buffer[:n],
|
|
FileName: fileName,
|
|
Offset: offset,
|
|
IsLast: isLast,
|
|
}, &reply)
|
|
|
|
if err != nil || !reply {
|
|
logger.Error("发送文件块失败", zap.Error(err))
|
|
}
|
|
|
|
offset += int64(n)
|
|
|
|
// 显示进度
|
|
progress := float64(offset) / float64(fileInfo.Size()) * 100
|
|
fmt.Printf("\r发送进度: %.2f%%", progress)
|
|
}
|
|
fmt.Println("\n文件发送完成!")
|
|
|
|
return nil
|
|
}
|
|
|