From 1aff1d7731651c85da81c607f9f51e681072094e Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 10 Jan 2026 22:32:16 +0800 Subject: [PATCH] :bug: Fix some bugs that introduced in previous changes --- DysonNetwork.Control/AppHost.cs | 3 +- DysonNetwork.Develop/appsettings.json | 2 +- ...10142132_NullableReplicaPoolId.Designer.cs | 760 ++++++++++++++++++ .../20260110142132_NullableReplicaPoolId.cs | 60 ++ .../Migrations/AppDatabaseModelSnapshot.cs | 4 +- .../Storage/FileObjectCleanupJob.cs | 62 +- DysonNetwork.Drive/Storage/FileService.cs | 12 +- DysonNetwork.Drive/appsettings.json | 7 +- DysonNetwork.Gateway/appsettings.json | 2 +- DysonNetwork.Insight/appsettings.json | 2 +- DysonNetwork.Messager/appsettings.json | 7 +- DysonNetwork.Pass/appsettings.json | 2 +- DysonNetwork.Ring/appsettings.json | 2 +- DysonNetwork.Shared/Models/CloudFileObject.cs | 4 +- DysonNetwork.Sphere/appsettings.json | 2 +- DysonNetwork.Zone/appsettings.json | 2 +- 16 files changed, 874 insertions(+), 59 deletions(-) create mode 100644 DysonNetwork.Drive/Migrations/20260110142132_NullableReplicaPoolId.Designer.cs create mode 100644 DysonNetwork.Drive/Migrations/20260110142132_NullableReplicaPoolId.cs diff --git a/DysonNetwork.Control/AppHost.cs b/DysonNetwork.Control/AppHost.cs index 40b80a24..d1d1bb39 100644 --- a/DysonNetwork.Control/AppHost.cs +++ b/DysonNetwork.Control/AppHost.cs @@ -36,7 +36,8 @@ var messagerService = builder.AddProject("messag .WithReference(passService) .WithReference(ringService) .WithReference(sphereService) - .WithReference(developService); + .WithReference(developService) + .WithReference(driveService); passService.WithReference(developService).WithReference(driveService); diff --git a/DysonNetwork.Develop/appsettings.json b/DysonNetwork.Develop/appsettings.json index 456e48c8..795fc90e 100644 --- a/DysonNetwork.Develop/appsettings.json +++ b/DysonNetwork.Develop/appsettings.json @@ -20,6 +20,6 @@ "PublicBasePath": "/develop" }, "Cache": { - "Serializer": "MessagePack" + "Serializer": "JSON" } } diff --git a/DysonNetwork.Drive/Migrations/20260110142132_NullableReplicaPoolId.Designer.cs b/DysonNetwork.Drive/Migrations/20260110142132_NullableReplicaPoolId.Designer.cs new file mode 100644 index 00000000..bbeb319f --- /dev/null +++ b/DysonNetwork.Drive/Migrations/20260110142132_NullableReplicaPoolId.Designer.cs @@ -0,0 +1,760 @@ +// +using System; +using System.Collections.Generic; +using DysonNetwork.Drive; +using DysonNetwork.Shared.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NodaTime; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace DysonNetwork.Drive.Migrations +{ + [DbContext(typeof(AppDatabase))] + [Migration("20260110142132_NullableReplicaPoolId")] + partial class NullableReplicaPoolId + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("DysonNetwork.Drive.Billing.QuotaRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("ExpiredAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expired_at"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Quota") + .HasColumnType("bigint") + .HasColumnName("quota"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_quota_records"); + + b.ToTable("quota_records", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Drive.Storage.Model.PersistentTask", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("CompletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("completed_at"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("description"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("character varying(21)") + .HasColumnName("discriminator"); + + b.Property("ErrorMessage") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("error_message"); + + b.Property("EstimatedDurationSeconds") + .HasColumnType("bigint") + .HasColumnName("estimated_duration_seconds"); + + b.Property("ExpiredAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expired_at"); + + b.Property("LastActivity") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_activity"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("name"); + + b.Property>("Parameters") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("parameters"); + + b.Property("Priority") + .HasColumnType("integer") + .HasColumnName("priority"); + + b.Property("Progress") + .HasColumnType("double precision") + .HasColumnName("progress"); + + b.Property>("Results") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("results"); + + b.Property("StartedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("started_at"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("TaskId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("task_id"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_tasks"); + + b.ToTable("tasks", (string)null); + + b.HasDiscriminator().HasValue("PersistentTask"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.FilePool", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("BillingConfig") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("billing_config"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(8192) + .HasColumnType("character varying(8192)") + .HasColumnName("description"); + + b.Property("IsHidden") + .HasColumnType("boolean") + .HasColumnName("is_hidden"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("name"); + + b.Property("PolicyConfig") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("policy_config"); + + b.Property("StorageConfig") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("storage_config"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_pools"); + + b.ToTable("pools", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnCloudFile", b => + { + b.Property("Id") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("BundleId") + .HasColumnType("uuid") + .HasColumnName("bundle_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Description") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("description"); + + b.Property("ExpiredAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expired_at"); + + b.Property>("FileMeta") + .HasColumnType("jsonb") + .HasColumnName("file_meta"); + + b.Property("HasCompression") + .HasColumnType("boolean") + .HasColumnName("has_compression"); + + b.Property("HasThumbnail") + .HasColumnType("boolean") + .HasColumnName("has_thumbnail"); + + b.Property("Hash") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("hash"); + + b.Property("IsEncrypted") + .HasColumnType("boolean") + .HasColumnName("is_encrypted"); + + b.Property("IsMarkedRecycle") + .HasColumnType("boolean") + .HasColumnName("is_marked_recycle"); + + b.Property("MimeType") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("mime_type"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("name"); + + b.Property("ObjectId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("object_id"); + + b.Property("PoolId") + .HasColumnType("uuid") + .HasColumnName("pool_id"); + + b.PrimitiveCollection("SensitiveMarks") + .HasColumnType("jsonb") + .HasColumnName("sensitive_marks"); + + b.Property("Size") + .HasColumnType("bigint") + .HasColumnName("size"); + + b.Property("StorageId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("storage_id"); + + b.Property("StorageUrl") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("storage_url"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("UploadedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("uploaded_at"); + + b.Property>("UserMeta") + .HasColumnType("jsonb") + .HasColumnName("user_meta"); + + b.HasKey("Id") + .HasName("pk_files"); + + b.HasIndex("BundleId") + .HasDatabaseName("ix_files_bundle_id"); + + b.HasIndex("ObjectId") + .HasDatabaseName("ix_files_object_id"); + + b.HasIndex("PoolId") + .HasDatabaseName("ix_files_pool_id"); + + b.ToTable("files", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnCloudFileIndex", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("FileId") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("file_id"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(8192) + .HasColumnType("character varying(8192)") + .HasColumnName("path"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_file_indexes"); + + b.HasIndex("FileId") + .HasDatabaseName("ix_file_indexes_file_id"); + + b.HasIndex("Path", "AccountId") + .HasDatabaseName("ix_file_indexes_path_account_id"); + + b.ToTable("file_indexes", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnFileBundle", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Description") + .HasMaxLength(8192) + .HasColumnType("character varying(8192)") + .HasColumnName("description"); + + b.Property("ExpiredAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expired_at"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("name"); + + b.Property("Passcode") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("passcode"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("slug"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_bundles"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_bundles_slug"); + + b.ToTable("bundles", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnFileObject", b => + { + b.Property("Id") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("HasCompression") + .HasColumnType("boolean") + .HasColumnName("has_compression"); + + b.Property("HasThumbnail") + .HasColumnType("boolean") + .HasColumnName("has_thumbnail"); + + b.Property("Hash") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("hash"); + + b.Property>("Meta") + .HasColumnType("jsonb") + .HasColumnName("meta"); + + b.Property("MimeType") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("mime_type"); + + b.Property("Size") + .HasColumnType("bigint") + .HasColumnName("size"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_file_objects"); + + b.ToTable("file_objects", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnFilePermission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("FileId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("file_id"); + + b.Property("Permission") + .HasColumnType("integer") + .HasColumnName("permission"); + + b.Property("SubjectId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("subject_id"); + + b.Property("SubjectType") + .HasColumnType("integer") + .HasColumnName("subject_type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_file_permissions"); + + b.ToTable("file_permissions", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnFileReplica", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("IsPrimary") + .HasColumnType("boolean") + .HasColumnName("is_primary"); + + b.Property("ObjectId") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("object_id"); + + b.Property("PoolId") + .HasColumnType("uuid") + .HasColumnName("pool_id"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("StorageId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("storage_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_file_replicas"); + + b.HasIndex("ObjectId") + .HasDatabaseName("ix_file_replicas_object_id"); + + b.HasIndex("PoolId") + .HasDatabaseName("ix_file_replicas_pool_id"); + + b.ToTable("file_replicas", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Drive.Storage.Model.PersistentUploadTask", b => + { + b.HasBaseType("DysonNetwork.Drive.Storage.Model.PersistentTask"); + + b.Property("BundleId") + .HasColumnType("uuid") + .HasColumnName("bundle_id"); + + b.Property("ChunkSize") + .HasColumnType("bigint") + .HasColumnName("chunk_size"); + + b.Property("ChunksCount") + .HasColumnType("integer") + .HasColumnName("chunks_count"); + + b.Property("ChunksUploaded") + .HasColumnType("integer") + .HasColumnName("chunks_uploaded"); + + b.Property("ContentType") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("content_type"); + + b.Property("EncryptPassword") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("encrypt_password"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("file_name"); + + b.Property("FileSize") + .HasColumnType("bigint") + .HasColumnName("file_size"); + + b.Property("Hash") + .IsRequired() + .HasColumnType("text") + .HasColumnName("hash"); + + b.Property("Path") + .HasColumnType("text") + .HasColumnName("path"); + + b.Property("PoolId") + .HasColumnType("uuid") + .HasColumnName("pool_id"); + + b.PrimitiveCollection>("UploadedChunks") + .IsRequired() + .HasColumnType("integer[]") + .HasColumnName("uploaded_chunks"); + + b.HasDiscriminator().HasValue("PersistentUploadTask"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnCloudFile", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnFileBundle", "Bundle") + .WithMany("Files") + .HasForeignKey("BundleId") + .HasConstraintName("fk_files_bundles_bundle_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnFileObject", "Object") + .WithMany() + .HasForeignKey("ObjectId") + .HasConstraintName("fk_files_file_objects_object_id"); + + b.HasOne("DysonNetwork.Shared.Models.FilePool", "Pool") + .WithMany() + .HasForeignKey("PoolId") + .HasConstraintName("fk_files_pools_pool_id"); + + b.Navigation("Bundle"); + + b.Navigation("Object"); + + b.Navigation("Pool"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnCloudFileIndex", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnCloudFile", "File") + .WithMany("FileIndexes") + .HasForeignKey("FileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_file_indexes_files_file_id"); + + b.Navigation("File"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnFileReplica", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnFileObject", "Object") + .WithMany("FileReplicas") + .HasForeignKey("ObjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_file_replicas_file_objects_object_id"); + + b.HasOne("DysonNetwork.Shared.Models.FilePool", "Pool") + .WithMany() + .HasForeignKey("PoolId") + .HasConstraintName("fk_file_replicas_pools_pool_id"); + + b.Navigation("Object"); + + b.Navigation("Pool"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnCloudFile", b => + { + b.Navigation("FileIndexes"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnFileBundle", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnFileObject", b => + { + b.Navigation("FileReplicas"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DysonNetwork.Drive/Migrations/20260110142132_NullableReplicaPoolId.cs b/DysonNetwork.Drive/Migrations/20260110142132_NullableReplicaPoolId.cs new file mode 100644 index 00000000..d6751fd2 --- /dev/null +++ b/DysonNetwork.Drive/Migrations/20260110142132_NullableReplicaPoolId.cs @@ -0,0 +1,60 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace DysonNetwork.Drive.Migrations +{ + /// + public partial class NullableReplicaPoolId : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_file_replicas_pools_pool_id", + table: "file_replicas"); + + migrationBuilder.AlterColumn( + name: "pool_id", + table: "file_replicas", + type: "uuid", + nullable: true, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AddForeignKey( + name: "fk_file_replicas_pools_pool_id", + table: "file_replicas", + column: "pool_id", + principalTable: "pools", + principalColumn: "id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_file_replicas_pools_pool_id", + table: "file_replicas"); + + migrationBuilder.AlterColumn( + name: "pool_id", + table: "file_replicas", + type: "uuid", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + oldClrType: typeof(Guid), + oldType: "uuid", + oldNullable: true); + + migrationBuilder.AddForeignKey( + name: "fk_file_replicas_pools_pool_id", + table: "file_replicas", + column: "pool_id", + principalTable: "pools", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/DysonNetwork.Drive/Migrations/AppDatabaseModelSnapshot.cs b/DysonNetwork.Drive/Migrations/AppDatabaseModelSnapshot.cs index a3effc72..09623911 100644 --- a/DysonNetwork.Drive/Migrations/AppDatabaseModelSnapshot.cs +++ b/DysonNetwork.Drive/Migrations/AppDatabaseModelSnapshot.cs @@ -590,7 +590,7 @@ namespace DysonNetwork.Drive.Migrations .HasColumnType("character varying(32)") .HasColumnName("object_id"); - b.Property("PoolId") + b.Property("PoolId") .HasColumnType("uuid") .HasColumnName("pool_id"); @@ -730,8 +730,6 @@ namespace DysonNetwork.Drive.Migrations b.HasOne("DysonNetwork.Shared.Models.FilePool", "Pool") .WithMany() .HasForeignKey("PoolId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() .HasConstraintName("fk_file_replicas_pools_pool_id"); b.Navigation("Object"); diff --git a/DysonNetwork.Drive/Storage/FileObjectCleanupJob.cs b/DysonNetwork.Drive/Storage/FileObjectCleanupJob.cs index 91c778ff..40d253e5 100644 --- a/DysonNetwork.Drive/Storage/FileObjectCleanupJob.cs +++ b/DysonNetwork.Drive/Storage/FileObjectCleanupJob.cs @@ -45,43 +45,39 @@ public class FileObjectCleanupJob(AppDatabase db, FileService fileService, ILogg .Where(r => r.ObjectId == fileObject.Id) .ToListAsync(); - foreach (var replica in replicas) + foreach (var replica in replicas.Where(r => r.PoolId.HasValue)) { - var dest = await fileService.GetRemoteStorageConfig(replica.PoolId); - if (dest != null) + var dest = await fileService.GetRemoteStorageConfig(replica.PoolId!.Value); + if (dest == null) continue; + var client = fileService.CreateMinioClient(dest); + if (client == null) continue; + try { - var client = fileService.CreateMinioClient(dest); - if (client != null) + await client.RemoveObjectAsync( + new RemoveObjectArgs() + .WithBucket(dest.Bucket) + .WithObject(replica.StorageId) + ); + if (fileObject.HasCompression) { - try - { - await client.RemoveObjectAsync( - new RemoveObjectArgs() - .WithBucket(dest.Bucket) - .WithObject(replica.StorageId) - ); - if (fileObject.HasCompression) - { - await client.RemoveObjectAsync( - new RemoveObjectArgs() - .WithBucket(dest.Bucket) - .WithObject(replica.StorageId + ".compressed") - ); - } - if (fileObject.HasThumbnail) - { - await client.RemoveObjectAsync( - new RemoveObjectArgs() - .WithBucket(dest.Bucket) - .WithObject(replica.StorageId + ".thumbnail") - ); - } - } - catch (Exception ex) - { - logger.LogError(ex, "Failed to delete orphaned file object {ObjectId} from remote storage", fileObject.Id); - } + await client.RemoveObjectAsync( + new RemoveObjectArgs() + .WithBucket(dest.Bucket) + .WithObject(replica.StorageId + ".compressed") + ); } + if (fileObject.HasThumbnail) + { + await client.RemoveObjectAsync( + new RemoveObjectArgs() + .WithBucket(dest.Bucket) + .WithObject(replica.StorageId + ".thumbnail") + ); + } + } + catch (Exception ex) + { + logger.LogError(ex, "Failed to delete orphaned file object {ObjectId} from remote storage", fileObject.Id); } } diff --git a/DysonNetwork.Drive/Storage/FileService.cs b/DysonNetwork.Drive/Storage/FileService.cs index 3ad7d33c..f51d86f2 100644 --- a/DysonNetwork.Drive/Storage/FileService.cs +++ b/DysonNetwork.Drive/Storage/FileService.cs @@ -204,7 +204,7 @@ public class FileService( }; } - private async Task<(string processingPath, bool isTempFile)> ProcessEncryptionAsync( + private Task<(string processingPath, bool isTempFile)> ProcessEncryptionAsync( string fileId, string managedTempPath, string? encryptPassword, @@ -213,7 +213,7 @@ public class FileService( ) { if (string.IsNullOrWhiteSpace(encryptPassword)) - return (managedTempPath, true); + return Task.FromResult((managedTempPath, true)); if (!pool.PolicyConfig.AllowEncryption) throw new InvalidOperationException("Encryption is not allowed in this pool"); @@ -227,7 +227,7 @@ public class FileService( file.MimeType = "application/octet-stream"; file.Size = new FileInfo(encryptedPath).Length; - return (encryptedPath, true); + return Task.FromResult((encryptedPath, true)); } private async Task SaveFileToDatabaseAsync(SnCloudFile file) @@ -248,7 +248,7 @@ public class FileService( { Id = Guid.NewGuid(), ObjectId = file.Id, - PoolId = file.PoolId!.Value, + PoolId = file.PoolId, StorageId = file.StorageId ?? file.Id, Status = SnFileReplicaStatus.Available, IsPrimary = true @@ -616,7 +616,7 @@ public class FileService( .Where(r => objectIds.Contains(r.ObjectId)) .ToListAsync(); - foreach (var poolGroup in replicas.GroupBy(r => r.PoolId)) + foreach (var poolGroup in replicas.Where(r => r.PoolId.HasValue).GroupBy(r => r.PoolId!.Value)) { var dest = await GetRemoteStorageConfig(poolGroup.Key); if (dest is null) @@ -860,4 +860,4 @@ file class UpdatableCloudFile(SnCloudFile file) .SetProperty(f => f.UserMeta, userMeta) .SetProperty(f => f.IsMarkedRecycle, IsMarkedRecycle); } -} +} \ No newline at end of file diff --git a/DysonNetwork.Drive/appsettings.json b/DysonNetwork.Drive/appsettings.json index 34349e10..bf82719e 100644 --- a/DysonNetwork.Drive/appsettings.json +++ b/DysonNetwork.Drive/appsettings.json @@ -74,11 +74,6 @@ "FromName": "Alphabot", "SubjectPrefix": "Solar Network" }, - "RealtimeChat": { - "Endpoint": "https://solar-network-im44o8gq.livekit.cloud", - "ApiKey": "APIs6TiL8wj3A4j", - "ApiSecret": "SffxRneIwTnlHPtEf3zicmmv3LUEl7xXael4PvWZrEhE" - }, "GeoIp": { "DatabasePath": "./Keys/GeoLite2-City.mmdb" }, @@ -112,7 +107,7 @@ } }, "Cache": { - "Serializer": "MessagePack" + "Serializer": "JSON" }, "KnownProxies": [ "127.0.0.1", diff --git a/DysonNetwork.Gateway/appsettings.json b/DysonNetwork.Gateway/appsettings.json index 4d8788bc..8ccaeb86 100644 --- a/DysonNetwork.Gateway/appsettings.json +++ b/DysonNetwork.Gateway/appsettings.json @@ -6,7 +6,7 @@ } }, "Cache": { - "Serializer": "MessagePack" + "Serializer": "JSON" }, "AllowedHosts": "*", "SiteUrl": "http://localhost:3000", diff --git a/DysonNetwork.Insight/appsettings.json b/DysonNetwork.Insight/appsettings.json index b2da6a03..4fed26e8 100644 --- a/DysonNetwork.Insight/appsettings.json +++ b/DysonNetwork.Insight/appsettings.json @@ -20,7 +20,7 @@ "Insecure": true }, "Cache": { - "Serializer": "MessagePack" + "Serializer": "JSON" }, "Thinking": { "DefaultService": "deepseek-chat", diff --git a/DysonNetwork.Messager/appsettings.json b/DysonNetwork.Messager/appsettings.json index 860fa770..dffeee03 100644 --- a/DysonNetwork.Messager/appsettings.json +++ b/DysonNetwork.Messager/appsettings.json @@ -20,10 +20,15 @@ "Insecure": true }, "Cache": { - "Serializer": "MessagePack" + "Serializer": "JSON" }, "Service": { "Name": "DysonNetwork.Messager", "Url": "https://localhost:7100" + }, + "RealtimeChat": { + "Endpoint": "https://solar-network-im44o8gq.livekit.cloud", + "ApiKey": "APIs6TiL8wj3A4j", + "ApiSecret": "SffxRneIwTnlHPtEf3zicmmv3LUEl7xXael4PvWZrEhE" } } diff --git a/DysonNetwork.Pass/appsettings.json b/DysonNetwork.Pass/appsettings.json index d76eea34..4a3a3231 100644 --- a/DysonNetwork.Pass/appsettings.json +++ b/DysonNetwork.Pass/appsettings.json @@ -63,7 +63,7 @@ } }, "Cache": { - "Serializer": "MessagePack" + "Serializer": "JSON" }, "Payment": { "Auth": { diff --git a/DysonNetwork.Ring/appsettings.json b/DysonNetwork.Ring/appsettings.json index 9e44c5df..976981bb 100644 --- a/DysonNetwork.Ring/appsettings.json +++ b/DysonNetwork.Ring/appsettings.json @@ -45,7 +45,7 @@ "Url": "https://localhost:7259" }, "Cache": { - "Serializer": "MessagePack" + "Serializer": "JSON" }, "Etcd": { "Insecure": true diff --git a/DysonNetwork.Shared/Models/CloudFileObject.cs b/DysonNetwork.Shared/Models/CloudFileObject.cs index bc1955af..42d1ac9b 100644 --- a/DysonNetwork.Shared/Models/CloudFileObject.cs +++ b/DysonNetwork.Shared/Models/CloudFileObject.cs @@ -35,8 +35,8 @@ public class SnFileReplica : ModelBase [MaxLength(32)] public string ObjectId { get; set; } public SnFileObject Object { get; set; } = null!; - public Guid PoolId { get; set; } - public FilePool Pool { get; set; } = null!; + public Guid? PoolId { get; set; } + public FilePool? Pool { get; set; } = null!; [MaxLength(128)] public string StorageId { get; set; } = null!; diff --git a/DysonNetwork.Sphere/appsettings.json b/DysonNetwork.Sphere/appsettings.json index 292bc2e5..8023a12a 100644 --- a/DysonNetwork.Sphere/appsettings.json +++ b/DysonNetwork.Sphere/appsettings.json @@ -35,7 +35,7 @@ "Insecure": true }, "Cache": { - "Serializer": "MessagePack" + "Serializer": "JSON" }, "Service": { "Name": "DysonNetwork.Sphere", diff --git a/DysonNetwork.Zone/appsettings.json b/DysonNetwork.Zone/appsettings.json index d816d41a..6d2e9101 100644 --- a/DysonNetwork.Zone/appsettings.json +++ b/DysonNetwork.Zone/appsettings.json @@ -18,7 +18,7 @@ "PublicBasePath": "/zone" }, "Cache": { - "Serializer": "MessagePack" + "Serializer": "JSON" }, "Sites": { "BasePath": "SiteData"