From 3632b32384d8803a10b14cdd3bf6d9d9f9ee29c8 Mon Sep 17 00:00:00 2001 From: xc Date: Wed, 17 Sep 2025 16:32:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0rdp=E8=BF=9C=E7=A8=8B?= =?UTF-8?q?=E4=BC=A0=E8=BE=93=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scagent/core/FileRpc.go | 113 ++++++- scagent/go.mod | 9 +- scagent/go.sum | 42 ++- scagent/proto/fileupload.proto | 40 +++ scagent/proto/fileupload/fileupload.pb.go | 313 ++++++++++++++++++ .../proto/fileupload/fileupload_grpc.pb.go | 121 +++++++ 6 files changed, 611 insertions(+), 27 deletions(-) create mode 100644 scagent/proto/fileupload.proto create mode 100644 scagent/proto/fileupload/fileupload.pb.go create mode 100644 scagent/proto/fileupload/fileupload_grpc.pb.go diff --git a/scagent/core/FileRpc.go b/scagent/core/FileRpc.go index 74a27f9..b48b186 100644 --- a/scagent/core/FileRpc.go +++ b/scagent/core/FileRpc.go @@ -5,6 +5,7 @@ import ( "os" "path" "path/filepath" + pb "scagent/proto/fileupload" "scagent/util" "strings" "time" @@ -13,7 +14,9 @@ import ( ) // FileService 提供文件传输服务 -type FileService struct{} +type FileService struct { + pb.UnimplementedFileUploadServiceServer +} // FileChunk 表示文件分片 type FileChunk struct { @@ -30,27 +33,73 @@ type ZipBlock struct { SelFile []string // 选中的文件 } -// Upload 接收文件分片并写入到本地文件 -func (f *FileService) Upload(chunk *FileChunk, reply *bool) error { - // 打开或创建文件,使用追加模式 - file, err := os.OpenFile(chunk.FileName, os.O_WRONLY|os.O_CREATE, 0644) - if err != nil { - return err - } - defer file.Close() +// 处理文件上传 +// dirpath 目标文件存放位置 +func (f *FileService) Upload(stream pb.FileUploadService_UploadFileServer, dirpath string) error { + var ( + file *os.File + fileInfo *pb.FileInfo + ) + // 启用日志 + logger := util.NewProductionLogger() + defer logger.Sync() - // 移动到指定偏移量 - if _, err := file.Seek(chunk.Offset, io.SeekStart); err != nil { - return err + // 检查目录是否存在 + if _, err := os.Stat(dirpath); os.IsNotExist(err) { + // 目录不存在,创建目录 + if err := os.MkdirAll(dirpath, 0755); err != nil { + return err + } } - // 写入数据 - if _, err := file.Write(chunk.Data); err != nil { - return err + for { + // 接收客户端发送的文件块 + chunk, err := stream.Recv() + if err == io.EOF { + // 所有块接收完毕,关闭文件并返回响应 + if file != nil { + file.Close() + } + // 客户端关闭流,上传完成 + logger.Info("UploadFile", zap.String("msg", "Client closed stream")) + return nil + } + if err != nil { + return err + } + // 处理第一个块,包含文件元信息 + if chunk.ChunkIndex == 0 && fileInfo == nil { + fileInfo = chunk.Info + if fileInfo == nil { + logger.Error("UploadFile", zap.String("msg", "fileInfo is nil")) + return nil + } + // 创建文件保存路径 + filePath := filepath.Join(dirpath, fileInfo.FileName) + // 打开或创建文件,使用追加模式 + file, err = os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0644) + if err != nil { + return err + } + logger.Info("开始接收文件", zap.String("filename", fileInfo.FileName), zap.String("path", filePath)) + } + // 写入文件内容 + if file != nil && len(chunk.Content) > 0 { + _, err = file.Write(chunk.Content) + if err != nil { + logger.Error("UploadFile", zap.String("msg", "写入文件失败"), zap.Error(err)) + return nil + } + + // 打印上传进度 + if chunk.ChunkIndex%10 == 0 { // 每10个块打印一次 + progress := float64(chunk.ChunkIndex+1) / float64(chunk.TotalChunks) * 100 + logger.Info("UploadFile", zap.String("msg", "文件上传进度"), zap.Float64("progress", progress), zap.Int("chunkIndex", int(chunk.ChunkIndex+1)), zap.Int("totalChunks", int(chunk.TotalChunks))) + } + } + } - *reply = true - return nil } // 压缩文件 @@ -74,14 +123,42 @@ func (f *FileService) Compress(args *ZipBlock, reply *string) error { logger.Info("压缩文件", zap.String("filename", zpFileName), zap.String("path", realFilePath)) }() // ZIP 文件的实际路径 - ziprl := path.Join("./sync_zips/", zpFileName) + ziprl := path.Join(args.Basepath, "/sync_zips", zpFileName) // zip 创建成功后 rest := <-taskId // 如果压缩包生成成功以后再执行 if strings.EqualFold(strings.ToLower(rest), "arcok") { // 返回压缩包名称 *reply = ziprl + // 发送文件到远程服务器上 + } return nil } + +// 接收传送来的文件存储在指定的目录下 +func (f *FileService) Download(args *FileChunk, reply *bool) error { + // 启用日志 + logger := util.NewProductionLogger() + defer logger.Sync() + // 实际路径 + realFilePath := filepath.Join(args.FileName) + logger.Info("Download", zap.String("realFilePath", realFilePath)) + // 打开或创建文件,使用追加模式 + file, err := os.OpenFile(realFilePath, os.O_WRONLY|os.O_CREATE, 0644) + if err != nil { + return err + } + defer file.Close() + // 移动到指定偏移量 + if _, err := file.Seek(args.Offset, io.SeekStart); err != nil { + return err + } + // 写入数据 + if _, err := file.Write(args.Data); err != nil { + return err + } + *reply = true + return nil +} diff --git a/scagent/go.mod b/scagent/go.mod index ab982b5..787d827 100644 --- a/scagent/go.mod +++ b/scagent/go.mod @@ -7,6 +7,7 @@ require ( github.com/schollz/progressbar/v3 v3.18.0 github.com/shirou/gopsutil/v3 v3.20.10 go.uber.org/zap v1.27.0 + google.golang.org/grpc v1.75.1 google.golang.org/protobuf v1.36.8 gopkg.in/ini.v1 v1.67.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 @@ -15,10 +16,12 @@ require ( require ( github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/go-ole/go-ole v1.2.4 // indirect - github.com/google/go-cmp v0.6.0 // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/rivo/uniseg v0.4.7 // indirect go.uber.org/multierr v1.10.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/term v0.28.0 // indirect + golang.org/x/net v0.41.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/term v0.32.0 // indirect + golang.org/x/text v0.26.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect ) diff --git a/scagent/go.sum b/scagent/go.sum index 469ff2d..c52e698 100644 --- a/scagent/go.sum +++ b/scagent/go.sum @@ -7,10 +7,18 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= @@ -27,17 +35,39 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= +go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= +go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= +go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI= +google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/scagent/proto/fileupload.proto b/scagent/proto/fileupload.proto new file mode 100644 index 0000000..7cb98ed --- /dev/null +++ b/scagent/proto/fileupload.proto @@ -0,0 +1,40 @@ +syntax = "proto3"; + +package fileupload; + +option go_package = "./fileupload"; + +// 文件上传服务定义 +service FileUploadService { + // 上传文件的 RPC 方法,使用流式传输 + rpc UploadFile (stream FileChunk) returns (UploadResponse); +} + +// 文件数据块 +message FileChunk { + // 文件元信息,只在第一个数据块中包含 + FileInfo info = 1; + // 文件数据 + bytes content = 2; + // 当前块的序号 + int32 chunk_index = 3; + // 总块数 + int32 total_chunks = 4; +} + +// 文件元信息 +message FileInfo { + string file_name = 1; // 文件名 + int64 file_size = 2; // 文件大小(字节) + string content_type = 3; // 文件类型 + string upload_path = 4; // 上传路径 +} + +// 上传响应 +message UploadResponse { + bool success = 1; // 是否成功 + string message = 2; // 响应消息 + string file_path = 3; // 服务器保存路径 + int64 received_size = 4; // 接收的文件大小 +} + \ No newline at end of file diff --git a/scagent/proto/fileupload/fileupload.pb.go b/scagent/proto/fileupload/fileupload.pb.go new file mode 100644 index 0000000..4b68eea --- /dev/null +++ b/scagent/proto/fileupload/fileupload.pb.go @@ -0,0 +1,313 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.6 +// protoc v6.30.2 +// source: fileupload.proto + +package fileupload + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// 文件数据块 +type FileChunk struct { + state protoimpl.MessageState `protogen:"open.v1"` + // 文件元信息,只在第一个数据块中包含 + Info *FileInfo `protobuf:"bytes,1,opt,name=info,proto3" json:"info,omitempty"` + // 文件数据 + Content []byte `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` + // 当前块的序号 + ChunkIndex int32 `protobuf:"varint,3,opt,name=chunk_index,json=chunkIndex,proto3" json:"chunk_index,omitempty"` + // 总块数 + TotalChunks int32 `protobuf:"varint,4,opt,name=total_chunks,json=totalChunks,proto3" json:"total_chunks,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FileChunk) Reset() { + *x = FileChunk{} + mi := &file_fileupload_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FileChunk) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FileChunk) ProtoMessage() {} + +func (x *FileChunk) ProtoReflect() protoreflect.Message { + mi := &file_fileupload_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FileChunk.ProtoReflect.Descriptor instead. +func (*FileChunk) Descriptor() ([]byte, []int) { + return file_fileupload_proto_rawDescGZIP(), []int{0} +} + +func (x *FileChunk) GetInfo() *FileInfo { + if x != nil { + return x.Info + } + return nil +} + +func (x *FileChunk) GetContent() []byte { + if x != nil { + return x.Content + } + return nil +} + +func (x *FileChunk) GetChunkIndex() int32 { + if x != nil { + return x.ChunkIndex + } + return 0 +} + +func (x *FileChunk) GetTotalChunks() int32 { + if x != nil { + return x.TotalChunks + } + return 0 +} + +// 文件元信息 +type FileInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + FileName string `protobuf:"bytes,1,opt,name=file_name,json=fileName,proto3" json:"file_name,omitempty"` // 文件名 + FileSize int64 `protobuf:"varint,2,opt,name=file_size,json=fileSize,proto3" json:"file_size,omitempty"` // 文件大小(字节) + ContentType string `protobuf:"bytes,3,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` // 文件类型 + UploadPath string `protobuf:"bytes,4,opt,name=upload_path,json=uploadPath,proto3" json:"upload_path,omitempty"` // 上传路径 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FileInfo) Reset() { + *x = FileInfo{} + mi := &file_fileupload_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FileInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FileInfo) ProtoMessage() {} + +func (x *FileInfo) ProtoReflect() protoreflect.Message { + mi := &file_fileupload_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FileInfo.ProtoReflect.Descriptor instead. +func (*FileInfo) Descriptor() ([]byte, []int) { + return file_fileupload_proto_rawDescGZIP(), []int{1} +} + +func (x *FileInfo) GetFileName() string { + if x != nil { + return x.FileName + } + return "" +} + +func (x *FileInfo) GetFileSize() int64 { + if x != nil { + return x.FileSize + } + return 0 +} + +func (x *FileInfo) GetContentType() string { + if x != nil { + return x.ContentType + } + return "" +} + +func (x *FileInfo) GetUploadPath() string { + if x != nil { + return x.UploadPath + } + return "" +} + +// 上传响应 +type UploadResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` // 是否成功 + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` // 响应消息 + FilePath string `protobuf:"bytes,3,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"` // 服务器保存路径 + ReceivedSize int64 `protobuf:"varint,4,opt,name=received_size,json=receivedSize,proto3" json:"received_size,omitempty"` // 接收的文件大小 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UploadResponse) Reset() { + *x = UploadResponse{} + mi := &file_fileupload_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadResponse) ProtoMessage() {} + +func (x *UploadResponse) ProtoReflect() protoreflect.Message { + mi := &file_fileupload_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadResponse.ProtoReflect.Descriptor instead. +func (*UploadResponse) Descriptor() ([]byte, []int) { + return file_fileupload_proto_rawDescGZIP(), []int{2} +} + +func (x *UploadResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +func (x *UploadResponse) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *UploadResponse) GetFilePath() string { + if x != nil { + return x.FilePath + } + return "" +} + +func (x *UploadResponse) GetReceivedSize() int64 { + if x != nil { + return x.ReceivedSize + } + return 0 +} + +var File_fileupload_proto protoreflect.FileDescriptor + +const file_fileupload_proto_rawDesc = "" + + "\n" + + "\x10fileupload.proto\x12\n" + + "fileupload\"\x93\x01\n" + + "\tFileChunk\x12(\n" + + "\x04info\x18\x01 \x01(\v2\x14.fileupload.FileInfoR\x04info\x12\x18\n" + + "\acontent\x18\x02 \x01(\fR\acontent\x12\x1f\n" + + "\vchunk_index\x18\x03 \x01(\x05R\n" + + "chunkIndex\x12!\n" + + "\ftotal_chunks\x18\x04 \x01(\x05R\vtotalChunks\"\x88\x01\n" + + "\bFileInfo\x12\x1b\n" + + "\tfile_name\x18\x01 \x01(\tR\bfileName\x12\x1b\n" + + "\tfile_size\x18\x02 \x01(\x03R\bfileSize\x12!\n" + + "\fcontent_type\x18\x03 \x01(\tR\vcontentType\x12\x1f\n" + + "\vupload_path\x18\x04 \x01(\tR\n" + + "uploadPath\"\x86\x01\n" + + "\x0eUploadResponse\x12\x18\n" + + "\asuccess\x18\x01 \x01(\bR\asuccess\x12\x18\n" + + "\amessage\x18\x02 \x01(\tR\amessage\x12\x1b\n" + + "\tfile_path\x18\x03 \x01(\tR\bfilePath\x12#\n" + + "\rreceived_size\x18\x04 \x01(\x03R\freceivedSize2V\n" + + "\x11FileUploadService\x12A\n" + + "\n" + + "UploadFile\x12\x15.fileupload.FileChunk\x1a\x1a.fileupload.UploadResponse(\x01B\x0eZ\f./fileuploadb\x06proto3" + +var ( + file_fileupload_proto_rawDescOnce sync.Once + file_fileupload_proto_rawDescData []byte +) + +func file_fileupload_proto_rawDescGZIP() []byte { + file_fileupload_proto_rawDescOnce.Do(func() { + file_fileupload_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_fileupload_proto_rawDesc), len(file_fileupload_proto_rawDesc))) + }) + return file_fileupload_proto_rawDescData +} + +var file_fileupload_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_fileupload_proto_goTypes = []any{ + (*FileChunk)(nil), // 0: fileupload.FileChunk + (*FileInfo)(nil), // 1: fileupload.FileInfo + (*UploadResponse)(nil), // 2: fileupload.UploadResponse +} +var file_fileupload_proto_depIdxs = []int32{ + 1, // 0: fileupload.FileChunk.info:type_name -> fileupload.FileInfo + 0, // 1: fileupload.FileUploadService.UploadFile:input_type -> fileupload.FileChunk + 2, // 2: fileupload.FileUploadService.UploadFile:output_type -> fileupload.UploadResponse + 2, // [2:3] is the sub-list for method output_type + 1, // [1:2] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_fileupload_proto_init() } +func file_fileupload_proto_init() { + if File_fileupload_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_fileupload_proto_rawDesc), len(file_fileupload_proto_rawDesc)), + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_fileupload_proto_goTypes, + DependencyIndexes: file_fileupload_proto_depIdxs, + MessageInfos: file_fileupload_proto_msgTypes, + }.Build() + File_fileupload_proto = out.File + file_fileupload_proto_goTypes = nil + file_fileupload_proto_depIdxs = nil +} diff --git a/scagent/proto/fileupload/fileupload_grpc.pb.go b/scagent/proto/fileupload/fileupload_grpc.pb.go new file mode 100644 index 0000000..9e1bb0e --- /dev/null +++ b/scagent/proto/fileupload/fileupload_grpc.pb.go @@ -0,0 +1,121 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v6.30.2 +// source: fileupload.proto + +package fileupload + +import ( + context "context" + + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + FileUploadService_UploadFile_FullMethodName = "/fileupload.FileUploadService/UploadFile" +) + +// FileUploadServiceClient is the client API for FileUploadService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// 文件上传服务定义 +type FileUploadServiceClient interface { + // 上传文件的 RPC 方法,使用流式传输 + UploadFile(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[FileChunk, UploadResponse], error) +} + +type fileUploadServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewFileUploadServiceClient(cc grpc.ClientConnInterface) FileUploadServiceClient { + return &fileUploadServiceClient{cc} +} + +func (c *fileUploadServiceClient) UploadFile(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[FileChunk, UploadResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &FileUploadService_ServiceDesc.Streams[0], FileUploadService_UploadFile_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[FileChunk, UploadResponse]{ClientStream: stream} + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type FileUploadService_UploadFileClient = grpc.ClientStreamingClient[FileChunk, UploadResponse] + +// FileUploadServiceServer is the server API for FileUploadService service. +// All implementations must embed UnimplementedFileUploadServiceServer +// for forward compatibility. +// +// 文件上传服务定义 +type FileUploadServiceServer interface { + // 上传文件的 RPC 方法,使用流式传输 + UploadFile(grpc.ClientStreamingServer[FileChunk, UploadResponse]) error + mustEmbedUnimplementedFileUploadServiceServer() +} + +// UnimplementedFileUploadServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedFileUploadServiceServer struct{} + +func (UnimplementedFileUploadServiceServer) UploadFile(grpc.ClientStreamingServer[FileChunk, UploadResponse]) error { + return status.Errorf(codes.Unimplemented, "method UploadFile not implemented") +} +func (UnimplementedFileUploadServiceServer) mustEmbedUnimplementedFileUploadServiceServer() {} +func (UnimplementedFileUploadServiceServer) testEmbeddedByValue() {} + +// UnsafeFileUploadServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to FileUploadServiceServer will +// result in compilation errors. +type UnsafeFileUploadServiceServer interface { + mustEmbedUnimplementedFileUploadServiceServer() +} + +func RegisterFileUploadServiceServer(s grpc.ServiceRegistrar, srv FileUploadServiceServer) { + // If the following call pancis, it indicates UnimplementedFileUploadServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&FileUploadService_ServiceDesc, srv) +} + +func _FileUploadService_UploadFile_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(FileUploadServiceServer).UploadFile(&grpc.GenericServerStream[FileChunk, UploadResponse]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type FileUploadService_UploadFileServer = grpc.ClientStreamingServer[FileChunk, UploadResponse] + +// FileUploadService_ServiceDesc is the grpc.ServiceDesc for FileUploadService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var FileUploadService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "fileupload.FileUploadService", + HandlerType: (*FileUploadServiceServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "UploadFile", + Handler: _FileUploadService_UploadFile_Handler, + ClientStreams: true, + }, + }, + Metadata: "fileupload.proto", +}