diff --git a/ZR.Admin.Grpc/Protos/FileTransfer.proto b/ZR.Admin.Grpc/Protos/FileTransfer.proto new file mode 100644 index 0000000..fa4306d --- /dev/null +++ b/ZR.Admin.Grpc/Protos/FileTransfer.proto @@ -0,0 +1,54 @@ +syntax = "proto3"; + +option csharp_namespace = "ZR.Admin.Grpc"; + +package filetransfer; + +service FileTransfer { + rpc InitUpload (InitUploadRequest) returns (InitUploadResponse); + rpc UploadChunk (stream UploadChunkRequest) returns (UploadChunkResponse); + rpc CompleteUpload (CompleteUploadRequest) returns (CompleteUploadResponse); + rpc CheckUploadStatus (CheckUploadStatusRequest) returns (CheckUploadStatusResponse); +} + +message InitUploadRequest { + string file_name = 1; + int64 file_size = 2; + string file_hash = 3; +} + +message InitUploadResponse { + string session_id = 1; + int64 uploaded_bytes = 2; +} + +message UploadChunkRequest { + string session_id = 1; + bytes chunk_data = 2; + int64 offset = 3; +} + +message UploadChunkResponse { + int64 uploaded_bytes = 1; +} + +message CompleteUploadRequest { + string session_id = 1; + string file_hash = 2; +} + +message CompleteUploadResponse { + bool success = 1; + string message = 2; +} + +message CheckUploadStatusRequest { + string file_name = 1; + string file_hash = 2; +} + +message CheckUploadStatusResponse { + string session_id = 1; + int64 uploaded_bytes = 2; + bool exists = 3; +} \ No newline at end of file diff --git a/ZR.Admin.Grpc/Services/FileTransferService.cs b/ZR.Admin.Grpc/Services/FileTransferService.cs new file mode 100644 index 0000000..e5cfaf1 --- /dev/null +++ b/ZR.Admin.Grpc/Services/FileTransferService.cs @@ -0,0 +1,109 @@ +using Grpc.Core; +using ZR.Admin.Grpc; + +namespace GrpcService.Services +{ + public class FileTransferService : FileTransfer.FileTransferBase + { + private readonly string _storagePath = "Îļþ"; + private readonly IUploadSessionManager _sessionManager; + + public FileTransferService(IUploadSessionManager sessionManager) + { + Directory.CreateDirectory(_storagePath); + _sessionManager = sessionManager; + } + + public override Task InitUpload(InitUploadRequest request, ServerCallContext context) + { + var sessionId = _sessionManager.CreateSession(request.FileName, request.FileSize, request.FileHash); + var uploadedBytes = _sessionManager.GetUploadedBytes(sessionId); + + return Task.FromResult(new InitUploadResponse + { + SessionId = sessionId, + UploadedBytes = uploadedBytes + }); + } + + public override async Task UploadChunk(IAsyncStreamReader requestStream, ServerCallContext context) + { + UploadChunkRequest currentRequest = null; + var response = new UploadChunkResponse(); + + while (await requestStream.MoveNext()) + { + currentRequest = requestStream.Current; + var session = _sessionManager.GetSession(currentRequest.SessionId); + + if (session == null) + { + throw new RpcException(new Status(StatusCode.NotFound, "Session not found")); + } + + using (var fileStream = new FileStream(session.TempFilePath, FileMode.OpenOrCreate, FileAccess.Write)) + { + fileStream.Seek(currentRequest.Offset, SeekOrigin.Begin); + await fileStream.WriteAsync(currentRequest.ChunkData.ToByteArray(), 0, currentRequest.ChunkData.Length); + } + + _sessionManager.UpdateSessionProgress(currentRequest.SessionId, currentRequest.Offset + currentRequest.ChunkData.Length); + response.UploadedBytes = currentRequest.Offset + currentRequest.ChunkData.Length; + } + + return response; + } + + public override async Task CompleteUpload(CompleteUploadRequest request, ServerCallContext context) + { + var session = _sessionManager.GetSession(request.SessionId); + if (session == null) + { + return await Task.FromResult(new CompleteUploadResponse + { + Success = false, + Message = "Session not found" + }); + } + + // Verify file hash if needed + if (!string.IsNullOrEmpty(request.FileHash)) + { + var actualHash = await FileHelper.GetQuickFileIdentity(session.TempFilePath); + if (actualHash != request.FileHash) + { + return await Task.FromResult(new CompleteUploadResponse + { + Success = false, + Message = "File hash mismatch" + }); + } + } + + // Move temp file to final location + var finalPath = Path.Combine(_storagePath, session.FileName); + //var finalPath = FileHelper.GetUniqueFilePath(_storagePath, session.FileName); + File.Move(session.TempFilePath, finalPath, true); + + _sessionManager.CompleteSession(request.SessionId); + + return await Task.FromResult(new CompleteUploadResponse + { + Success = true, + Message = "File uploaded successfully" + }); + } + + public override Task CheckUploadStatus(CheckUploadStatusRequest request, ServerCallContext context) + { + var session = _sessionManager.FindSession(request.FileName, request.FileHash); + + return Task.FromResult(new CheckUploadStatusResponse + { + SessionId = session?.SessionId ?? "", + UploadedBytes = session?.UploadedBytes ?? 0, + Exists = session != null + }); + } + } +} \ No newline at end of file diff --git a/ZR.Admin.Grpc/ZR.Admin.Grpc.csproj b/ZR.Admin.Grpc/ZR.Admin.Grpc.csproj index 27c5eef..cdb498a 100644 --- a/ZR.Admin.Grpc/ZR.Admin.Grpc.csproj +++ b/ZR.Admin.Grpc/ZR.Admin.Grpc.csproj @@ -6,10 +6,15 @@ enable + + + + +