From b03e9bea5e0d5033d6e9c12505366144bdd8d257 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 10 Jan 2026 23:44:51 +0800 Subject: [PATCH] :recycle: Completely remove the upload task --- DysonNetwork.Drive/AppDatabase.cs | 1 - ...10154021_RemoveUploadTaskAgain.Designer.cs | 688 ++++++++++++++++++ .../20260110154021_RemoveUploadTaskAgain.cs | 155 ++++ .../Migrations/AppDatabaseModelSnapshot.cs | 72 -- .../Startup/BroadcastEventHandler.cs | 34 +- .../Storage/Model/FileUploadModels.cs | 1 - .../Storage/PersistentTaskService.cs | 100 ++- 7 files changed, 946 insertions(+), 105 deletions(-) create mode 100644 DysonNetwork.Drive/Migrations/20260110154021_RemoveUploadTaskAgain.Designer.cs create mode 100644 DysonNetwork.Drive/Migrations/20260110154021_RemoveUploadTaskAgain.cs diff --git a/DysonNetwork.Drive/AppDatabase.cs b/DysonNetwork.Drive/AppDatabase.cs index 2843a2c6..dcc3860f 100644 --- a/DysonNetwork.Drive/AppDatabase.cs +++ b/DysonNetwork.Drive/AppDatabase.cs @@ -29,7 +29,6 @@ public class AppDatabase( public DbSet FileIndexes { get; set; } public DbSet Tasks { get; set; } = null!; - public DbSet UploadTasks { get; set; } = null!; // Backward compatibility protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { diff --git a/DysonNetwork.Drive/Migrations/20260110154021_RemoveUploadTaskAgain.Designer.cs b/DysonNetwork.Drive/Migrations/20260110154021_RemoveUploadTaskAgain.Designer.cs new file mode 100644 index 00000000..ac7c43f3 --- /dev/null +++ b/DysonNetwork.Drive/Migrations/20260110154021_RemoveUploadTaskAgain.Designer.cs @@ -0,0 +1,688 @@ +// +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("20260110154021_RemoveUploadTaskAgain")] + partial class RemoveUploadTaskAgain + { + /// + 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("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); + }); + + 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.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/20260110154021_RemoveUploadTaskAgain.cs b/DysonNetwork.Drive/Migrations/20260110154021_RemoveUploadTaskAgain.cs new file mode 100644 index 00000000..a596dd2a --- /dev/null +++ b/DysonNetwork.Drive/Migrations/20260110154021_RemoveUploadTaskAgain.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace DysonNetwork.Drive.Migrations +{ + /// + public partial class RemoveUploadTaskAgain : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "bundle_id", + table: "tasks"); + + migrationBuilder.DropColumn( + name: "chunk_size", + table: "tasks"); + + migrationBuilder.DropColumn( + name: "chunks_count", + table: "tasks"); + + migrationBuilder.DropColumn( + name: "chunks_uploaded", + table: "tasks"); + + migrationBuilder.DropColumn( + name: "content_type", + table: "tasks"); + + migrationBuilder.DropColumn( + name: "discriminator", + table: "tasks"); + + migrationBuilder.DropColumn( + name: "encrypt_password", + table: "tasks"); + + migrationBuilder.DropColumn( + name: "file_name", + table: "tasks"); + + migrationBuilder.DropColumn( + name: "file_size", + table: "tasks"); + + migrationBuilder.DropColumn( + name: "hash", + table: "tasks"); + + migrationBuilder.DropColumn( + name: "path", + table: "tasks"); + + migrationBuilder.DropColumn( + name: "pool_id", + table: "tasks"); + + migrationBuilder.DropColumn( + name: "uploaded_chunks", + table: "tasks"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "bundle_id", + table: "tasks", + type: "uuid", + nullable: true); + + migrationBuilder.AddColumn( + name: "chunk_size", + table: "tasks", + type: "bigint", + nullable: true); + + migrationBuilder.AddColumn( + name: "chunks_count", + table: "tasks", + type: "integer", + nullable: true); + + migrationBuilder.AddColumn( + name: "chunks_uploaded", + table: "tasks", + type: "integer", + nullable: true); + + migrationBuilder.AddColumn( + name: "content_type", + table: "tasks", + type: "character varying(128)", + maxLength: 128, + nullable: true); + + migrationBuilder.AddColumn( + name: "discriminator", + table: "tasks", + type: "character varying(21)", + maxLength: 21, + nullable: false, + defaultValue: ""); + + migrationBuilder.AddColumn( + name: "encrypt_password", + table: "tasks", + type: "character varying(256)", + maxLength: 256, + nullable: true); + + migrationBuilder.AddColumn( + name: "file_name", + table: "tasks", + type: "character varying(256)", + maxLength: 256, + nullable: true); + + migrationBuilder.AddColumn( + name: "file_size", + table: "tasks", + type: "bigint", + nullable: true); + + migrationBuilder.AddColumn( + name: "hash", + table: "tasks", + type: "text", + nullable: true); + + migrationBuilder.AddColumn( + name: "path", + table: "tasks", + type: "text", + nullable: true); + + migrationBuilder.AddColumn( + name: "pool_id", + table: "tasks", + type: "uuid", + nullable: true); + + migrationBuilder.AddColumn>( + name: "uploaded_chunks", + table: "tasks", + type: "integer[]", + nullable: true); + } + } +} diff --git a/DysonNetwork.Drive/Migrations/AppDatabaseModelSnapshot.cs b/DysonNetwork.Drive/Migrations/AppDatabaseModelSnapshot.cs index 09623911..917c557e 100644 --- a/DysonNetwork.Drive/Migrations/AppDatabaseModelSnapshot.cs +++ b/DysonNetwork.Drive/Migrations/AppDatabaseModelSnapshot.cs @@ -100,12 +100,6 @@ namespace DysonNetwork.Drive.Migrations .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)") @@ -173,10 +167,6 @@ namespace DysonNetwork.Drive.Migrations .HasName("pk_tasks"); b.ToTable("tasks", (string)null); - - b.HasDiscriminator().HasValue("PersistentTask"); - - b.UseTphMappingStrategy(); }); modelBuilder.Entity("DysonNetwork.Shared.Models.FilePool", b => @@ -620,68 +610,6 @@ namespace DysonNetwork.Drive.Migrations 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") diff --git a/DysonNetwork.Drive/Startup/BroadcastEventHandler.cs b/DysonNetwork.Drive/Startup/BroadcastEventHandler.cs index 11525bda..b497757d 100644 --- a/DysonNetwork.Drive/Startup/BroadcastEventHandler.cs +++ b/DysonNetwork.Drive/Startup/BroadcastEventHandler.cs @@ -159,9 +159,37 @@ public class BroadcastEventHandler( var fileToUpdate = await scopedDb.Files.AsNoTracking().FirstAsync(f => f.Id == fileId); // Find the upload task associated with this file - var uploadTask = await scopedDb.Tasks - .OfType() - .FirstOrDefaultAsync(t => t.FileName == fileToUpdate.Name && t.FileSize == fileToUpdate.Size); + var baseTask = await scopedDb.Tasks + .Where(t => t.Type == TaskType.FileUpload) + .FirstOrDefaultAsync(); + + var uploadTask = baseTask != null ? new PersistentUploadTask + { + Id = baseTask.Id, + TaskId = baseTask.TaskId, + Name = baseTask.Name, + Description = baseTask.Description, + Type = baseTask.Type, + Status = baseTask.Status, + AccountId = baseTask.AccountId, + Progress = baseTask.Progress, + Parameters = baseTask.Parameters, + Results = baseTask.Results, + ErrorMessage = baseTask.ErrorMessage, + StartedAt = baseTask.StartedAt, + CompletedAt = baseTask.CompletedAt, + ExpiredAt = baseTask.ExpiredAt, + LastActivity = baseTask.LastActivity, + Priority = baseTask.Priority, + EstimatedDurationSeconds = baseTask.EstimatedDurationSeconds, + CreatedAt = baseTask.CreatedAt, + UpdatedAt = baseTask.UpdatedAt + } : null; + + if (uploadTask != null && (uploadTask.FileName != fileToUpdate.Name || uploadTask.FileSize != fileToUpdate.Size)) + { + uploadTask = null; + } if (fileToUpdate.IsEncrypted) { diff --git a/DysonNetwork.Drive/Storage/Model/FileUploadModels.cs b/DysonNetwork.Drive/Storage/Model/FileUploadModels.cs index c2a2f804..e8bcab2a 100644 --- a/DysonNetwork.Drive/Storage/Model/FileUploadModels.cs +++ b/DysonNetwork.Drive/Storage/Model/FileUploadModels.cs @@ -161,7 +161,6 @@ public class PersistentTask : ModelBase public long? EstimatedDurationSeconds { get; set; } } -// Backward compatibility - UploadTask inherits from PersistentTask public class PersistentUploadTask : PersistentTask { public PersistentUploadTask() diff --git a/DysonNetwork.Drive/Storage/PersistentTaskService.cs b/DysonNetwork.Drive/Storage/PersistentTaskService.cs index 24be1338..521719bd 100644 --- a/DysonNetwork.Drive/Storage/PersistentTaskService.cs +++ b/DysonNetwork.Drive/Storage/PersistentTaskService.cs @@ -664,16 +664,54 @@ public class PersistentTaskService( if (cachedTask is not null) return cachedTask; - var task = await db.Tasks - .OfType() - .FirstOrDefaultAsync(t => t.TaskId == taskId && t.Status == TaskStatus.InProgress); + var baseTask = await db.Tasks + .FirstOrDefaultAsync(t => t.TaskId == taskId && t.Type == TaskType.FileUpload && t.Status == TaskStatus.InProgress); - if (task is not null) - await SetCacheAsync(task); + if (baseTask is null) + return null; + var task = ConvertToUploadTask(baseTask); + await SetCacheAsync(task); return task; } + /// + /// Converts a base PersistentTask to PersistentUploadTask + /// + private PersistentUploadTask ConvertToUploadTask(PersistentTask baseTask) + { + return new PersistentUploadTask + { + Id = baseTask.Id, + TaskId = baseTask.TaskId, + Name = baseTask.Name, + Description = baseTask.Description, + Type = baseTask.Type, + Status = baseTask.Status, + AccountId = baseTask.AccountId, + Progress = baseTask.Progress, + Parameters = baseTask.Parameters, + Results = baseTask.Results, + ErrorMessage = baseTask.ErrorMessage, + StartedAt = baseTask.StartedAt, + CompletedAt = baseTask.CompletedAt, + ExpiredAt = baseTask.ExpiredAt, + LastActivity = baseTask.LastActivity, + Priority = baseTask.Priority, + EstimatedDurationSeconds = baseTask.EstimatedDurationSeconds, + CreatedAt = baseTask.CreatedAt, + UpdatedAt = baseTask.UpdatedAt + }; + } + + /// + /// Converts a list of base PersistentTasks to PersistentUploadTasks + /// + private List ConvertToUploadTasks(List baseTasks) + { + return baseTasks.Select(ConvertToUploadTask).ToList(); + } + /// /// Updates chunk upload progress /// @@ -697,8 +735,7 @@ public class PersistentTaskService( // Use ExecuteUpdateAsync to update the Parameters dictionary directly var updatedRows = await db.Tasks - .OfType() - .Where(t => t.TaskId == taskId) + .Where(t => t.TaskId == taskId && t.Type == TaskType.FileUpload) .ExecuteUpdateAsync(setters => setters .SetProperty(t => t.Parameters, ParameterHelper.Untyped(parameters)) .SetProperty(t => t.LastActivity, now) @@ -754,7 +791,7 @@ public class PersistentTaskService( int limit = 50 ) { - var query = db.Tasks.OfType().Where(t => t.AccountId == accountId); + var query = db.Tasks.Where(t => t.Type == TaskType.FileUpload && t.AccountId == accountId); // Apply status filter if (status.HasValue) @@ -766,19 +803,9 @@ public class PersistentTaskService( var totalCount = await query.CountAsync(); // Apply sorting - IOrderedQueryable orderedQuery; + IOrderedQueryable orderedQuery; switch (sortBy?.ToLower()) { - case "filename": - orderedQuery = sortDescending - ? query.OrderByDescending(t => t.FileName) - : query.OrderBy(t => t.FileName); - break; - case "filesize": - orderedQuery = sortDescending - ? query.OrderByDescending(t => t.FileSize) - : query.OrderBy(t => t.FileSize); - break; case "created": orderedQuery = sortDescending ? query.OrderByDescending(t => t.CreatedAt) @@ -798,11 +825,27 @@ public class PersistentTaskService( } // Apply pagination - var items = await orderedQuery + var baseTasks = await orderedQuery .Skip(offset) .Take(limit) .ToListAsync(); + var items = ConvertToUploadTasks(baseTasks); + + // Sort by derived properties if needed (filename, filesize) + if (sortBy?.ToLower() == "filename") + { + items = sortDescending + ? items.OrderByDescending(t => t.FileName).ToList() + : items.OrderBy(t => t.FileName).ToList(); + } + else if (sortBy?.ToLower() == "filesize") + { + items = sortDescending + ? items.OrderByDescending(t => t.FileSize).ToList() + : items.OrderBy(t => t.FileSize).ToList(); + } + return (items, totalCount); } @@ -811,11 +854,12 @@ public class PersistentTaskService( /// public async Task GetUserUploadStatsAsync(Guid accountId) { - var tasks = await db.Tasks - .OfType() - .Where(t => t.AccountId == accountId) + var baseTasks = await db.Tasks + .Where(t => t.Type == TaskType.FileUpload && t.AccountId == accountId) .ToListAsync(); + var tasks = ConvertToUploadTasks(baseTasks); + var stats = new UserUploadStats { TotalTasks = tasks.Count, @@ -850,8 +894,7 @@ public class PersistentTaskService( public async Task CleanupUserFailedTasksAsync(Guid accountId) { var failedTasks = await db.Tasks - .OfType() - .Where(t => t.AccountId == accountId && + .Where(t => t.Type == TaskType.FileUpload && t.AccountId == accountId && (t.Status == TaskStatus.Failed || t.Status == TaskStatus.Expired)) .ToListAsync(); @@ -883,12 +926,13 @@ public class PersistentTaskService( /// public async Task> GetRecentUserTasksAsync(Guid accountId, int limit = 10) { - return await db.Tasks - .OfType() - .Where(t => t.AccountId == accountId) + var baseTasks = await db.Tasks + .Where(t => t.Type == TaskType.FileUpload && t.AccountId == accountId) .OrderByDescending(t => t.LastActivity) .Take(limit) .ToListAsync(); + + return ConvertToUploadTasks(baseTasks); } ///