Compare commits
	
		
			2 Commits
		
	
	
		
			387246a95c
			...
			92ab7a1a2a
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 92ab7a1a2a | |||
| 28067d18f6 | 
| @@ -66,9 +66,4 @@ | |||||||
|     <ItemGroup> |     <ItemGroup> | ||||||
|       <ProjectReference Include="..\DysonNetwork.Shared\DysonNetwork.Shared.csproj" /> |       <ProjectReference Include="..\DysonNetwork.Shared\DysonNetwork.Shared.csproj" /> | ||||||
|     </ItemGroup> |     </ItemGroup> | ||||||
|  |  | ||||||
|     <ItemGroup> |  | ||||||
|       <Compile Remove="Storage\FileReferenceServiceGrpc.cs" /> |  | ||||||
|     </ItemGroup> |  | ||||||
|  |  | ||||||
| </Project> | </Project> | ||||||
|   | |||||||
							
								
								
									
										127
									
								
								DysonNetwork.Drive/Storage/FileReferenceServiceGrpc.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								DysonNetwork.Drive/Storage/FileReferenceServiceGrpc.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,127 @@ | |||||||
|  | using System.Threading.Tasks; | ||||||
|  | using DysonNetwork.Shared.Proto; | ||||||
|  | using Google.Protobuf.WellKnownTypes; | ||||||
|  | using Grpc.Core; | ||||||
|  | using NodaTime; | ||||||
|  | using Duration = NodaTime.Duration; | ||||||
|  |  | ||||||
|  | namespace DysonNetwork.Drive.Storage | ||||||
|  | { | ||||||
|  |     public class FileReferenceServiceGrpc(FileReferenceService fileReferenceService) : Shared.Proto.FileReferenceService.FileReferenceServiceBase | ||||||
|  |     { | ||||||
|  |         public override async Task<Shared.Proto.CloudFileReference> CreateReference(CreateReferenceRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             Instant? expiredAt = null; | ||||||
|  |             if (request.ExpiredAt != null) | ||||||
|  |             { | ||||||
|  |                 expiredAt = Instant.FromUnixTimeSeconds(request.ExpiredAt.Seconds); | ||||||
|  |             } | ||||||
|  |             else if (request.Duration != null) | ||||||
|  |             { | ||||||
|  |                 expiredAt = SystemClock.Instance.GetCurrentInstant() + Duration.FromTimeSpan(request.Duration.ToTimeSpan()); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             var reference = await fileReferenceService.CreateReferenceAsync( | ||||||
|  |                 request.FileId, | ||||||
|  |                 request.Usage, | ||||||
|  |                 request.ResourceId, | ||||||
|  |                 expiredAt | ||||||
|  |             ); | ||||||
|  |             return reference.ToProtoValue(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<GetReferencesResponse> GetReferences(GetReferencesRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             var references = await fileReferenceService.GetReferencesAsync(request.FileId); | ||||||
|  |             var response = new GetReferencesResponse(); | ||||||
|  |             response.References.AddRange(references.Select(r => r.ToProtoValue())); | ||||||
|  |             return response; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<GetReferenceCountResponse> GetReferenceCount(GetReferenceCountRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             var count = await fileReferenceService.GetReferenceCountAsync(request.FileId); | ||||||
|  |             return new GetReferenceCountResponse { Count = count }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<GetReferencesResponse> GetResourceReferences(GetResourceReferencesRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             var references = await fileReferenceService.GetResourceReferencesAsync(request.ResourceId, request.Usage); | ||||||
|  |             var response = new GetReferencesResponse(); | ||||||
|  |             response.References.AddRange(references.Select(r => r.ToProtoValue())); | ||||||
|  |             return response; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<GetResourceFilesResponse> GetResourceFiles(GetResourceFilesRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             var files = await fileReferenceService.GetResourceFilesAsync(request.ResourceId, request.Usage); | ||||||
|  |             var response = new GetResourceFilesResponse(); | ||||||
|  |             response.Files.AddRange(files.Select(f => f.ToProtoValue())); | ||||||
|  |             return response; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<DeleteResourceReferencesResponse> DeleteResourceReferences(DeleteResourceReferencesRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             var deletedCount = await fileReferenceService.DeleteResourceReferencesAsync(request.ResourceId, request.Usage); | ||||||
|  |             return new DeleteResourceReferencesResponse { DeletedCount = deletedCount }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<DeleteReferenceResponse> DeleteReference(DeleteReferenceRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             var success = await fileReferenceService.DeleteReferenceAsync(Guid.Parse(request.ReferenceId)); | ||||||
|  |             return new DeleteReferenceResponse { Success = success }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<UpdateResourceFilesResponse> UpdateResourceFiles(UpdateResourceFilesRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             Instant? expiredAt = null; | ||||||
|  |             if (request.ExpiredAt != null) | ||||||
|  |             { | ||||||
|  |                 expiredAt = Instant.FromUnixTimeSeconds(request.ExpiredAt.Seconds); | ||||||
|  |             } | ||||||
|  |             else if (request.Duration != null) | ||||||
|  |             { | ||||||
|  |                 expiredAt = SystemClock.Instance.GetCurrentInstant() + Duration.FromTimeSpan(request.Duration.ToTimeSpan()); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             var references = await fileReferenceService.UpdateResourceFilesAsync( | ||||||
|  |                 request.ResourceId, | ||||||
|  |                 request.FileIds, | ||||||
|  |                 request.Usage, | ||||||
|  |                 expiredAt | ||||||
|  |             ); | ||||||
|  |             var response = new UpdateResourceFilesResponse(); | ||||||
|  |             response.References.AddRange(references.Select(r => r.ToProtoValue())); | ||||||
|  |             return response; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<SetReferenceExpirationResponse> SetReferenceExpiration(SetReferenceExpirationRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             Instant? expiredAt = null; | ||||||
|  |             if (request.ExpiredAt != null) | ||||||
|  |             { | ||||||
|  |                 expiredAt = Instant.FromUnixTimeSeconds(request.ExpiredAt.Seconds); | ||||||
|  |             } | ||||||
|  |             else if (request.Duration != null) | ||||||
|  |             { | ||||||
|  |                 expiredAt = SystemClock.Instance.GetCurrentInstant() + Duration.FromTimeSpan(request.Duration.ToTimeSpan()); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             var success = await fileReferenceService.SetReferenceExpirationAsync(Guid.Parse(request.ReferenceId), expiredAt); | ||||||
|  |             return new SetReferenceExpirationResponse { Success = success }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<SetFileReferencesExpirationResponse> SetFileReferencesExpiration(SetFileReferencesExpirationRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             var expiredAt = Instant.FromUnixTimeSeconds(request.ExpiredAt.Seconds); | ||||||
|  |             var updatedCount = await fileReferenceService.SetFileReferencesExpirationAsync(request.FileId, expiredAt); | ||||||
|  |             return new SetFileReferencesExpirationResponse { UpdatedCount = updatedCount }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<HasFileReferencesResponse> HasFileReferences(HasFileReferencesRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             var hasReferences = await fileReferenceService.HasFileReferencesAsync(request.FileId); | ||||||
|  |             return new HasFileReferencesResponse { HasReferences = hasReferences }; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -3,6 +3,7 @@ using FFMpegCore; | |||||||
| using System.Security.Cryptography; | using System.Security.Cryptography; | ||||||
| using DysonNetwork.Shared.Cache; | using DysonNetwork.Shared.Cache; | ||||||
| using DysonNetwork.Shared.Proto; | using DysonNetwork.Shared.Proto; | ||||||
|  | using Google.Protobuf.WellKnownTypes; | ||||||
| using Microsoft.EntityFrameworkCore; | using Microsoft.EntityFrameworkCore; | ||||||
| using Minio; | using Minio; | ||||||
| using Minio.DataModel.Args; | using Minio.DataModel.Args; | ||||||
| @@ -344,6 +345,68 @@ public class FileService( | |||||||
|         return file; |         return file; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public async Task<CloudFile> UpdateFileAsync(CloudFile file, FieldMask updateMask) | ||||||
|  |     { | ||||||
|  |         var existingFile = await db.Files.FirstOrDefaultAsync(f => f.Id == file.Id); | ||||||
|  |         if (existingFile == null) | ||||||
|  |         { | ||||||
|  |             throw new InvalidOperationException($"File with ID {file.Id} not found."); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         foreach (var path in updateMask.Paths) | ||||||
|  |         { | ||||||
|  |             switch (path) | ||||||
|  |             { | ||||||
|  |                 case "name": | ||||||
|  |                     existingFile.Name = file.Name; | ||||||
|  |                     break; | ||||||
|  |                 case "description": | ||||||
|  |                     existingFile.Description = file.Description; | ||||||
|  |                     break; | ||||||
|  |                 case "file_meta": | ||||||
|  |                     existingFile.FileMeta = file.FileMeta; | ||||||
|  |                     break; | ||||||
|  |                 case "user_meta": | ||||||
|  |                     existingFile.UserMeta = file.UserMeta; | ||||||
|  |                     break; | ||||||
|  |                 case "mime_type": | ||||||
|  |                     existingFile.MimeType = file.MimeType; | ||||||
|  |                     break; | ||||||
|  |                 case "hash": | ||||||
|  |                     existingFile.Hash = file.Hash; | ||||||
|  |                     break; | ||||||
|  |                 case "size": | ||||||
|  |                     existingFile.Size = file.Size; | ||||||
|  |                     break; | ||||||
|  |                 case "uploaded_at": | ||||||
|  |                     existingFile.UploadedAt = file.UploadedAt; | ||||||
|  |                     break; | ||||||
|  |                 case "uploaded_to": | ||||||
|  |                     existingFile.UploadedTo = file.UploadedTo; | ||||||
|  |                     break; | ||||||
|  |                 case "has_compression": | ||||||
|  |                     existingFile.HasCompression = file.HasCompression; | ||||||
|  |                     break; | ||||||
|  |                 case "is_marked_recycle": | ||||||
|  |                     existingFile.IsMarkedRecycle = file.IsMarkedRecycle; | ||||||
|  |                     break; | ||||||
|  |                 case "storage_id": | ||||||
|  |                     existingFile.StorageId = file.StorageId; | ||||||
|  |                     break; | ||||||
|  |                 case "storage_url": | ||||||
|  |                     existingFile.StorageUrl = file.StorageUrl; | ||||||
|  |                     break; | ||||||
|  |                 default: | ||||||
|  |                     logger.LogWarning("Attempted to update unknown field: {Field}", path); | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         await db.SaveChangesAsync(); | ||||||
|  |         await _PurgeCacheAsync(file.Id); | ||||||
|  |         return existingFile; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public async Task DeleteFileAsync(CloudFile file) |     public async Task DeleteFileAsync(CloudFile file) | ||||||
|     { |     { | ||||||
|         await DeleteFileDataAsync(file); |         await DeleteFileDataAsync(file); | ||||||
|   | |||||||
							
								
								
									
										167
									
								
								DysonNetwork.Drive/Storage/FileServiceGrpc.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								DysonNetwork.Drive/Storage/FileServiceGrpc.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,167 @@ | |||||||
|  | using System.Threading.Tasks; | ||||||
|  | using DysonNetwork.Shared.Proto; | ||||||
|  | using Google.Protobuf.WellKnownTypes; | ||||||
|  | using Grpc.Core; | ||||||
|  |  | ||||||
|  | namespace DysonNetwork.Drive.Storage | ||||||
|  | { | ||||||
|  |     public class FileServiceGrpc(FileService fileService) : Shared.Proto.FileService.FileServiceBase | ||||||
|  |     { | ||||||
|  |         public override async Task<Shared.Proto.CloudFile> GetFile(GetFileRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             var file = await fileService.GetFileAsync(request.Id); | ||||||
|  |             return file?.ToProtoValue() ?? throw new RpcException(new Status(StatusCode.NotFound, "File not found")); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<Shared.Proto.CloudFile> UpdateFile(UpdateFileRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             var file = await fileService.GetFileAsync(request.File.Id); | ||||||
|  |             if (file == null) | ||||||
|  |                 throw new RpcException(new Status(StatusCode.NotFound, "File not found")); | ||||||
|  |             var updatedFile = await fileService.UpdateFileAsync(file, request.UpdateMask); | ||||||
|  |             return updatedFile.ToProtoValue(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<Empty> DeleteFile(DeleteFileRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             var file = await fileService.GetFileAsync(request.Id); | ||||||
|  |             if (file == null) | ||||||
|  |             { | ||||||
|  |                 throw new RpcException(new Status(StatusCode.NotFound, "File not found")); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             await fileService.DeleteFileAsync(file); | ||||||
|  |             return new Empty(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<Shared.Proto.CloudFile> ProcessNewFile(IAsyncStreamReader<ProcessNewFileRequest> requestStream, | ||||||
|  |             ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             ProcessNewFileRequest? metadataRequest = null; | ||||||
|  |             var chunks = new List<byte[]>(); | ||||||
|  |  | ||||||
|  |             await foreach (var message in requestStream.ReadAllAsync()) | ||||||
|  |             { | ||||||
|  |                 if (message.DataCase == ProcessNewFileRequest.DataOneofCase.Metadata) | ||||||
|  |                 { | ||||||
|  |                     metadataRequest = message; | ||||||
|  |                 } | ||||||
|  |                 else if (message.DataCase == ProcessNewFileRequest.DataOneofCase.Chunk) | ||||||
|  |                 { | ||||||
|  |                     chunks.Add(message.Chunk.ToByteArray()); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (metadataRequest == null || metadataRequest.Metadata == null) | ||||||
|  |             { | ||||||
|  |                 throw new RpcException(new Status(StatusCode.InvalidArgument, "Missing file metadata")); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             var metadata = metadataRequest.Metadata; | ||||||
|  |             using var memoryStream = new MemoryStream(); | ||||||
|  |             foreach (var chunk in chunks) | ||||||
|  |             { | ||||||
|  |                 await memoryStream.WriteAsync(chunk); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             memoryStream.Position = 0; | ||||||
|  |  | ||||||
|  |             // Assuming you have an Account object available or can create a dummy one for now | ||||||
|  |             // You might need to adjust this based on how accounts are handled in your system | ||||||
|  |             var dummyAccount = new Account { Id = metadata.AccountId }; | ||||||
|  |  | ||||||
|  |             var cloudFile = await fileService.ProcessNewFileAsync( | ||||||
|  |                 dummyAccount, | ||||||
|  |                 metadata.FileId, | ||||||
|  |                 memoryStream, | ||||||
|  |                 metadata.FileName, | ||||||
|  |                 metadata.ContentType | ||||||
|  |             ); | ||||||
|  |             return cloudFile.ToProtoValue(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<Shared.Proto.CloudFile> UploadFileToRemote( | ||||||
|  |             IAsyncStreamReader<UploadFileToRemoteRequest> requestStream, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             UploadFileToRemoteRequest? metadataRequest = null; | ||||||
|  |             var chunks = new List<byte[]>(); | ||||||
|  |  | ||||||
|  |             await foreach (var message in requestStream.ReadAllAsync()) | ||||||
|  |             { | ||||||
|  |                 if (message.DataCase == UploadFileToRemoteRequest.DataOneofCase.Metadata) | ||||||
|  |                 { | ||||||
|  |                     metadataRequest = message; | ||||||
|  |                 } | ||||||
|  |                 else if (message.DataCase == UploadFileToRemoteRequest.DataOneofCase.Chunk) | ||||||
|  |                 { | ||||||
|  |                     chunks.Add(message.Chunk.ToByteArray()); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (metadataRequest == null || metadataRequest.Metadata == null) | ||||||
|  |             { | ||||||
|  |                 throw new RpcException(new Status(StatusCode.InvalidArgument, "Missing upload metadata")); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             var metadata = metadataRequest.Metadata; | ||||||
|  |             using var memoryStream = new MemoryStream(); | ||||||
|  |             foreach (var chunk in chunks) | ||||||
|  |             { | ||||||
|  |                 await memoryStream.WriteAsync(chunk); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             memoryStream.Position = 0; | ||||||
|  |  | ||||||
|  |             var file = await fileService.GetFileAsync(metadata.FileId); | ||||||
|  |             if (file == null) | ||||||
|  |             { | ||||||
|  |                 throw new RpcException(new Status(StatusCode.NotFound, "File not found")); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             var uploadedFile = await fileService.UploadFileToRemoteAsync( | ||||||
|  |                 file, | ||||||
|  |                 memoryStream, | ||||||
|  |                 metadata.TargetRemote, | ||||||
|  |                 metadata.Suffix | ||||||
|  |             ); | ||||||
|  |             return uploadedFile.ToProtoValue(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<Empty> DeleteFileData(DeleteFileDataRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             var file = await fileService.GetFileAsync(request.FileId); | ||||||
|  |             if (file == null) | ||||||
|  |             { | ||||||
|  |                 throw new RpcException(new Status(StatusCode.NotFound, "File not found")); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             await fileService.DeleteFileDataAsync(file); | ||||||
|  |             return new Empty(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<LoadFromReferenceResponse> LoadFromReference(LoadFromReferenceRequest request, | ||||||
|  |             ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             // Assuming CloudFileReferenceObject is a simple class/struct that holds an ID | ||||||
|  |             // You might need to define this or adjust the LoadFromReference method in FileService | ||||||
|  |             var references = request.ReferenceIds.Select(id => new CloudFileReferenceObject { Id = id }).ToList(); | ||||||
|  |             var files = await fileService.LoadFromReference(references); | ||||||
|  |             var response = new LoadFromReferenceResponse(); | ||||||
|  |             response.Files.AddRange(files.Where(f => f != null).Select(f => f!.ToProtoValue())); | ||||||
|  |             return response; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<IsReferencedResponse> IsReferenced(IsReferencedRequest request, | ||||||
|  |             ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             var isReferenced = await fileService.IsReferencedAsync(request.FileId); | ||||||
|  |             return new IsReferencedResponse { IsReferenced = isReferenced }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public override async Task<Empty> PurgeCache(PurgeCacheRequest request, ServerCallContext context) | ||||||
|  |         { | ||||||
|  |             await fileService._PurgeCacheAsync(request.FileId); | ||||||
|  |             return new Empty(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user