🧱 File service basis

This commit is contained in:
2025-07-14 03:01:51 +08:00
parent 387246a95c
commit 28067d18f6
3 changed files with 302 additions and 5 deletions

View File

@ -66,9 +66,4 @@
<ItemGroup>
<ProjectReference Include="..\DysonNetwork.Shared\DysonNetwork.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Storage\FileReferenceServiceGrpc.cs" />
</ItemGroup>
</Project>

View 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 };
}
}
}

View File

@ -0,0 +1,175 @@
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)
{
// Assuming UpdateFileAsync exists in FileService and handles the update_mask
// This is a placeholder, as the current FileService.cs doesn't have a direct UpdateFile method
// You might need to implement this logic in FileService based on your needs.
// For now, we'll just return the requested file.
var file = await fileService.GetFileAsync(request.File.Id);
if (file == null)
{
throw new RpcException(new Status(StatusCode.NotFound, "File not found"));
}
// Apply updates from request.File to 'file' based on request.UpdateMask
// This part requires more detailed implementation based on how you want to handle partial updates.
return file.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();
}
}
}