diff --git a/DysonNetwork.Drive/DysonNetwork.Drive.csproj b/DysonNetwork.Drive/DysonNetwork.Drive.csproj index 9edd5ba..19bfcab 100644 --- a/DysonNetwork.Drive/DysonNetwork.Drive.csproj +++ b/DysonNetwork.Drive/DysonNetwork.Drive.csproj @@ -67,4 +67,8 @@ + + + + diff --git a/DysonNetwork.Drive/Storage/CloudFile.cs b/DysonNetwork.Drive/Storage/CloudFile.cs index c5c6f35..6911dc2 100644 --- a/DysonNetwork.Drive/Storage/CloudFile.cs +++ b/DysonNetwork.Drive/Storage/CloudFile.cs @@ -1,9 +1,8 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using System.Text.Json.Serialization; using DysonNetwork.Shared.Data; -using DysonNetwork.Shared.Proto; using NodaTime; +using NodaTime.Serialization.Protobuf; namespace DysonNetwork.Drive.Storage; @@ -97,6 +96,46 @@ public class CloudFile : ModelBase, ICloudFile, IIdentifiedResource } public string ResourceIdentifier => $"file/{Id}"; + + /// + /// Converts the CloudFile to a protobuf message + /// + /// The protobuf message representation of this object + public Shared.Proto.CloudFile ToProtoValue() + { + var protoFile = new Shared.Proto.CloudFile + { + Id = Id, + Name = Name ?? string.Empty, + MimeType = MimeType ?? string.Empty, + Hash = Hash ?? string.Empty, + Size = Size, + HasCompression = HasCompression, + Url = StorageUrl ?? string.Empty, + ContentType = MimeType ?? string.Empty, + UploadedAt = UploadedAt?.ToTimestamp() + }; + + // Convert FileMeta dictionary + if (FileMeta != null) + { + foreach (var (key, value) in FileMeta) + { + protoFile.FileMeta[key] = Google.Protobuf.WellKnownTypes.Value.ForString(value?.ToString() ?? string.Empty); + } + } + + // Convert UserMeta dictionary + if (UserMeta != null) + { + foreach (var (key, value) in UserMeta) + { + protoFile.UserMeta[key] = Google.Protobuf.WellKnownTypes.Value.ForString(value?.ToString() ?? string.Empty); + } + } + + return protoFile; + } } public enum ContentSensitiveMark @@ -128,4 +167,21 @@ public class CloudFileReference : ModelBase /// Optional expiration date for the file reference /// public Instant? ExpiredAt { get; set; } + + /// + /// Converts the CloudFileReference to a protobuf message + /// + /// The protobuf message representation of this object + public Shared.Proto.CloudFileReference ToProtoValue() + { + return new Shared.Proto.CloudFileReference + { + Id = Id.ToString(), + FileId = FileId, + File = File?.ToProtoValue(), + Usage = Usage, + ResourceId = ResourceId, + ExpiredAt = ExpiredAt?.ToTimestamp() + }; + } } \ No newline at end of file diff --git a/DysonNetwork.Shared/Data/CloudFileReferenceObject.cs b/DysonNetwork.Shared/Data/CloudFileReferenceObject.cs index 37c0eab..b20826f 100644 --- a/DysonNetwork.Shared/Data/CloudFileReferenceObject.cs +++ b/DysonNetwork.Shared/Data/CloudFileReferenceObject.cs @@ -20,9 +20,9 @@ public class CloudFileReferenceObject : ModelBase, ICloudFile /// /// Converts the current object to its protobuf representation /// - public global::DysonNetwork.Shared.Proto.CloudFileReferenceObject ToProtoValue() + public Proto.CloudFile ToProtoValue() { - var proto = new global::DysonNetwork.Shared.Proto.CloudFileReferenceObject + var proto = new Proto.CloudFile { Id = Id, Name = Name, @@ -30,7 +30,6 @@ public class CloudFileReferenceObject : ModelBase, ICloudFile Hash = Hash ?? string.Empty, Size = Size, HasCompression = HasCompression, - // Backward compatibility fields ContentType = MimeType ?? string.Empty, Url = string.Empty // This should be set by the caller if needed }; diff --git a/DysonNetwork.Shared/Proto/account.proto b/DysonNetwork.Shared/Proto/account.proto index b7fad42..59afef5 100644 --- a/DysonNetwork.Shared/Proto/account.proto +++ b/DysonNetwork.Shared/Proto/account.proto @@ -55,8 +55,8 @@ message AccountProfile { google.protobuf.StringValue picture_id = 17; google.protobuf.StringValue background_id = 18; - CloudFileReferenceObject picture = 19; - CloudFileReferenceObject background = 20; + CloudFile picture = 19; + CloudFile background = 20; string account_id = 21; } diff --git a/DysonNetwork.Shared/Proto/file.proto b/DysonNetwork.Shared/Proto/file.proto index 593e2b7..92cd6f7 100644 --- a/DysonNetwork.Shared/Proto/file.proto +++ b/DysonNetwork.Shared/Proto/file.proto @@ -8,10 +8,11 @@ import "google/protobuf/timestamp.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/empty.proto"; import "google/protobuf/field_mask.proto"; +import "google/protobuf/duration.proto"; -// CloudFileReferenceObject represents a reference to a file stored in cloud storage. +// CloudFile represents a reference to a file stored in cloud storage. // It contains metadata about the file that won't change, helping to reduce database load. -message CloudFileReferenceObject { +message CloudFile { // Unique identifier for the file string id = 1; @@ -36,32 +37,44 @@ message CloudFileReferenceObject { // Indicates if the file is stored with compression bool has_compression = 8; - // URL to access the file (kept for backward compatibility) + // URL to access the file string url = 9; - // Content type of the file (kept for backward compatibility) + // Content type of the file string content_type = 10; - // When the file was uploaded (kept for backward compatibility) + // When the file was uploaded google.protobuf.Timestamp uploaded_at = 11; - - // Additional metadata (kept for backward compatibility) - map metadata = 12; } // Service for file operations service FileService { // Get file reference by ID - rpc GetFile(GetFileRequest) returns (CloudFileReferenceObject) {} - - // Create a new file reference - rpc CreateFile(CreateFileRequest) returns (CloudFileReferenceObject) {} + rpc GetFile(GetFileRequest) returns (CloudFile); // Update an existing file reference - rpc UpdateFile(UpdateFileRequest) returns (CloudFileReferenceObject) {} + rpc UpdateFile(UpdateFileRequest) returns (CloudFile); // Delete a file reference - rpc DeleteFile(DeleteFileRequest) returns (google.protobuf.Empty) {} + rpc DeleteFile(DeleteFileRequest) returns (google.protobuf.Empty); + + // Process and upload a new file + rpc ProcessNewFile(stream ProcessNewFileRequest) returns (CloudFile); + + // Upload a file to remote storage + rpc UploadFileToRemote(stream UploadFileToRemoteRequest) returns (CloudFile); + + // Delete file data from storage + rpc DeleteFileData(DeleteFileDataRequest) returns (google.protobuf.Empty); + + // Load files from references + rpc LoadFromReference(LoadFromReferenceRequest) returns (LoadFromReferenceResponse); + + // Check if a file is referenced by any resource + rpc IsReferenced(IsReferencedRequest) returns (IsReferencedResponse); + + // Purge cache for a file + rpc PurgeCache(PurgeCacheRequest) returns (google.protobuf.Empty); } // Request message for GetFile @@ -69,19 +82,220 @@ message GetFileRequest { string id = 1; } -// Request message for CreateFile -message CreateFileRequest { - CloudFileReferenceObject file = 1; -} - // Request message for UpdateFile message UpdateFileRequest { - CloudFileReferenceObject file = 1; + CloudFile file = 1; google.protobuf.FieldMask update_mask = 2; } // Request message for DeleteFile +message ProcessNewFileRequest { + oneof data { + FileMetadata metadata = 1; + bytes chunk = 2; + } +} + +message FileMetadata { + string file_id = 1; + string file_name = 2; + string content_type = 3; + string account_id = 4; +} + +message UploadFileToRemoteRequest { + oneof data { + UploadMetadata metadata = 1; + bytes chunk = 2; + } +} + +message UploadMetadata { + string file_id = 1; + string target_remote = 2; + string suffix = 3; + string content_type = 4; +} + message DeleteFileRequest { string id = 1; - bool hard_delete = 2; + bool purge = 2; +} + +message DeleteFileDataRequest { + string file_id = 1; + bool force = 2; +} + +message LoadFromReferenceRequest { + repeated string reference_ids = 1; +} + +message LoadFromReferenceResponse { + repeated CloudFile files = 1; +} + +message GetReferenceCountRequest { + string file_id = 1; +} + +message GetReferenceCountResponse { + int32 count = 1; +} + +message IsReferencedRequest { + string file_id = 1; +} + +message IsReferencedResponse { + bool is_referenced = 1; +} + +message PurgeCacheRequest { + string file_id = 1; +} + +// CloudFileReference represents a reference to a CloudFile with additional metadata +// about its usage in the system. +message CloudFileReference { + // Unique identifier for the reference + string id = 1; + + // Reference to the actual file + string file_id = 2; + + // The actual file data (optional, can be populated when needed) + CloudFile file = 3; + + // Description of how this file is being used + string usage = 4; + + // ID of the resource that this file is associated with + string resource_id = 5; + + // Optional expiration timestamp for the reference + google.protobuf.Timestamp expired_at = 6; +} + +// Request/Response messages for FileReferenceService +message CreateReferenceRequest { + string file_id = 1; + string usage = 2; + string resource_id = 3; + google.protobuf.Timestamp expired_at = 4; + google.protobuf.Duration duration = 5; // Alternative to expired_at +} + +message GetReferencesRequest { + string file_id = 1; +} + +message GetReferencesResponse { + repeated CloudFileReference references = 1; +} + +message GetResourceReferencesRequest { + string resource_id = 1; + string usage = 2; // Optional +} + +message GetResourceFilesRequest { + string resource_id = 1; + string usage = 2; // Optional +} + +message GetResourceFilesResponse { + repeated CloudFile files = 1; +} + +message DeleteResourceReferencesRequest { + string resource_id = 1; + string usage = 2; // Optional +} + +message DeleteResourceReferencesResponse { + int32 deleted_count = 1; +} + +message DeleteReferenceRequest { + string reference_id = 1; +} + +message DeleteReferenceResponse { + bool success = 1; +} + +message UpdateResourceFilesRequest { + string resource_id = 1; + repeated string file_ids = 2; + string usage = 3; + google.protobuf.Timestamp expired_at = 4; + google.protobuf.Duration duration = 5; // Alternative to expired_at +} + +message UpdateResourceFilesResponse { + repeated CloudFileReference references = 1; +} + +message SetReferenceExpirationRequest { + string reference_id = 1; + google.protobuf.Timestamp expired_at = 2; + google.protobuf.Duration duration = 3; // Alternative to expired_at +} + +message SetReferenceExpirationResponse { + bool success = 1; +} + +message SetFileReferencesExpirationRequest { + string file_id = 1; + google.protobuf.Timestamp expired_at = 2; +} + +message SetFileReferencesExpirationResponse { + int32 updated_count = 1; +} + +message HasFileReferencesRequest { + string file_id = 1; +} + +message HasFileReferencesResponse { + bool has_references = 1; +} + +// Service for managing file references +service FileReferenceService { + // Creates a new reference to a file for a specific resource + rpc CreateReference(CreateReferenceRequest) returns (CloudFileReference); + + // Gets all references to a file + rpc GetReferences(GetReferencesRequest) returns (GetReferencesResponse); + + // Gets the number of references to a file + rpc GetReferenceCount(GetReferenceCountRequest) returns (GetReferenceCountResponse); + + // Gets all references for a specific resource and optional usage + rpc GetResourceReferences(GetResourceReferencesRequest) returns (GetReferencesResponse); + + // Gets all files referenced by a resource with optional usage filter + rpc GetResourceFiles(GetResourceFilesRequest) returns (GetResourceFilesResponse); + + // Deletes references for a specific resource and optional usage + rpc DeleteResourceReferences(DeleteResourceReferencesRequest) returns (DeleteResourceReferencesResponse); + + // Deletes a specific file reference + rpc DeleteReference(DeleteReferenceRequest) returns (DeleteReferenceResponse); + + // Updates the files referenced by a resource + rpc UpdateResourceFiles(UpdateResourceFilesRequest) returns (UpdateResourceFilesResponse); + + // Updates the expiration time for a file reference + rpc SetReferenceExpiration(SetReferenceExpirationRequest) returns (SetReferenceExpirationResponse); + + // Updates the expiration time for all references to a file + rpc SetFileReferencesExpiration(SetFileReferencesExpirationRequest) returns (SetFileReferencesExpirationResponse); + + // Checks if a file has any references + rpc HasFileReferences(HasFileReferencesRequest) returns (HasFileReferencesResponse); } diff --git a/DysonNetwork.sln.DotSettings.user b/DysonNetwork.sln.DotSettings.user index 28064a5..c388d6b 100644 --- a/DysonNetwork.sln.DotSettings.user +++ b/DysonNetwork.sln.DotSettings.user @@ -43,6 +43,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded