🗑️ Remove imagesharp

This commit is contained in:
LittleSheep 2025-05-18 12:47:26 +08:00
parent 205ccd66b3
commit b40282e43a
6 changed files with 3511 additions and 82 deletions

View File

@ -1,16 +1,12 @@
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using tencentyun;
namespace DysonNetwork.Sphere.Chat; namespace DysonNetwork.Sphere.Chat;
public class RealtimeChatConfiguration public class RealtimeChatConfiguration
{ {
public string Provider { get; set; } = null!; public string Provider { get; set; } = null!;
public int AppId { get; set; }
[JsonIgnore] public string SecretKey { get; set; } = null!;
} }
[ApiController] [ApiController]
@ -20,46 +16,6 @@ public class RealtimeCallController(IConfiguration configuration, AppDatabase db
private readonly RealtimeChatConfiguration _config = private readonly RealtimeChatConfiguration _config =
configuration.GetSection("RealtimeChat").Get<RealtimeChatConfiguration>()!; configuration.GetSection("RealtimeChat").Get<RealtimeChatConfiguration>()!;
[HttpGet]
public ActionResult<RealtimeChatConfiguration> GetConfiguration()
{
return _config;
}
public class RealtimeChatToken
{
public RealtimeChatConfiguration Config { get; set; } = null!;
public string Token { get; set; } = null!;
}
[HttpGet("{roomId:guid}")]
[Authorize]
public async Task<ActionResult<RealtimeChatToken>> GetToken(Guid roomId)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
var member = await db.ChatMembers
.Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == roomId)
.FirstOrDefaultAsync();
if (member == null || member.Role < ChatMemberRole.Member)
return StatusCode(403,
"You need to be a normal member to get the token for joining the realtime chatroom."
);
var ongoingCall = await cs.GetCallOngoingAsync(roomId);
if (ongoingCall is null) return BadRequest("No ongoing call.");
var api = new TLSSigAPIv2(_config.AppId, _config.SecretKey);
var sig = api.GenSig(currentUser.Name);
if (sig is null) return StatusCode(500, "Failed to generate the token.");
return Ok(new RealtimeChatToken
{
Config = _config,
Token = sig
});
}
[HttpPost("{roomId:guid}")] [HttpPost("{roomId:guid}")]
[Authorize] [Authorize]
public async Task<IActionResult> StartCall(Guid roomId) public async Task<IActionResult> StartCall(Guid roomId)

View File

@ -25,7 +25,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" /> <PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="Blurhash.ImageSharp" Version="4.0.0" /> <PackageReference Include="BlurHashSharp.SkiaSharp" Version="1.3.4" />
<PackageReference Include="CorePush" Version="4.3.0" /> <PackageReference Include="CorePush" Version="4.3.0" />
<PackageReference Include="EFCore.BulkExtensions" Version="9.0.1" /> <PackageReference Include="EFCore.BulkExtensions" Version="9.0.1" />
<PackageReference Include="EFCore.BulkExtensions.PostgreSql" Version="9.0.1" /> <PackageReference Include="EFCore.BulkExtensions.PostgreSql" Version="9.0.1" />
@ -58,12 +58,8 @@
<PackageReference Include="Quartz" Version="3.14.0" /> <PackageReference Include="Quartz" Version="3.14.0" />
<PackageReference Include="Quartz.AspNetCore" Version="3.14.0" /> <PackageReference Include="Quartz.AspNetCore" Version="3.14.0" />
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.14.0" /> <PackageReference Include="Quartz.Extensions.Hosting" Version="3.14.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.5" />
<PackageReference Include="SixLabors.ImageSharp.Web" Version="3.1.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="8.1.0" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="8.1.0" />
<PackageReference Include="tls-sig-api-v2" Version="1.0.1" />
<PackageReference Include="tusdotnet" Version="2.8.1" /> <PackageReference Include="tusdotnet" Version="2.8.1" />
</ItemGroup> </ItemGroup>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,103 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using NodaTime;
#nullable disable
namespace DysonNetwork.Sphere.Migrations
{
/// <inheritdoc />
public partial class OptimizeDataStructure : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "chat_statuses");
migrationBuilder.CreateTable(
name: "chat_read_receipts",
columns: table => new
{
message_id = table.Column<Guid>(type: "uuid", nullable: false),
sender_id = table.Column<Guid>(type: "uuid", nullable: false),
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_chat_read_receipts", x => new { x.message_id, x.sender_id });
table.ForeignKey(
name: "fk_chat_read_receipts_chat_members_sender_id",
column: x => x.sender_id,
principalTable: "chat_members",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_chat_read_receipts_chat_messages_message_id",
column: x => x.message_id,
principalTable: "chat_messages",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "ix_chat_read_receipts_message_id_sender_id",
table: "chat_read_receipts",
columns: new[] { "message_id", "sender_id" },
unique: true);
migrationBuilder.CreateIndex(
name: "ix_chat_read_receipts_sender_id",
table: "chat_read_receipts",
column: "sender_id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "chat_read_receipts");
migrationBuilder.CreateTable(
name: "chat_statuses",
columns: table => new
{
message_id = table.Column<Guid>(type: "uuid", nullable: false),
sender_id = table.Column<Guid>(type: "uuid", nullable: false),
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
read_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_chat_statuses", x => new { x.message_id, x.sender_id });
table.ForeignKey(
name: "fk_chat_statuses_chat_members_sender_id",
column: x => x.sender_id,
principalTable: "chat_members",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_chat_statuses_chat_messages_message_id",
column: x => x.message_id,
principalTable: "chat_messages",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "ix_chat_statuses_message_id_sender_id",
table: "chat_statuses",
columns: new[] { "message_id", "sender_id" },
unique: true);
migrationBuilder.CreateIndex(
name: "ix_chat_statuses_sender_id",
table: "chat_statuses",
column: "sender_id");
}
}
}

View File

@ -1143,7 +1143,7 @@ namespace DysonNetwork.Sphere.Migrations
b.ToTable("chat_reactions", (string)null); b.ToTable("chat_reactions", (string)null);
}); });
modelBuilder.Entity("DysonNetwork.Sphere.Chat.MessageStatus", b => modelBuilder.Entity("DysonNetwork.Sphere.Chat.MessageReadReceipt", b =>
{ {
b.Property<Guid>("MessageId") b.Property<Guid>("MessageId")
.HasColumnType("uuid") .HasColumnType("uuid")
@ -1161,25 +1161,21 @@ namespace DysonNetwork.Sphere.Migrations
.HasColumnType("timestamp with time zone") .HasColumnType("timestamp with time zone")
.HasColumnName("deleted_at"); .HasColumnName("deleted_at");
b.Property<Instant>("ReadAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("read_at");
b.Property<Instant>("UpdatedAt") b.Property<Instant>("UpdatedAt")
.HasColumnType("timestamp with time zone") .HasColumnType("timestamp with time zone")
.HasColumnName("updated_at"); .HasColumnName("updated_at");
b.HasKey("MessageId", "SenderId") b.HasKey("MessageId", "SenderId")
.HasName("pk_chat_statuses"); .HasName("pk_chat_read_receipts");
b.HasIndex("SenderId") b.HasIndex("SenderId")
.HasDatabaseName("ix_chat_statuses_sender_id"); .HasDatabaseName("ix_chat_read_receipts_sender_id");
b.HasIndex("MessageId", "SenderId") b.HasIndex("MessageId", "SenderId")
.IsUnique() .IsUnique()
.HasDatabaseName("ix_chat_statuses_message_id_sender_id"); .HasDatabaseName("ix_chat_read_receipts_message_id_sender_id");
b.ToTable("chat_statuses", (string)null); b.ToTable("chat_read_receipts", (string)null);
}); });
modelBuilder.Entity("DysonNetwork.Sphere.Chat.RealtimeCall", b => modelBuilder.Entity("DysonNetwork.Sphere.Chat.RealtimeCall", b =>
@ -2850,21 +2846,21 @@ namespace DysonNetwork.Sphere.Migrations
b.Navigation("Sender"); b.Navigation("Sender");
}); });
modelBuilder.Entity("DysonNetwork.Sphere.Chat.MessageStatus", b => modelBuilder.Entity("DysonNetwork.Sphere.Chat.MessageReadReceipt", b =>
{ {
b.HasOne("DysonNetwork.Sphere.Chat.Message", "Message") b.HasOne("DysonNetwork.Sphere.Chat.Message", "Message")
.WithMany("Statuses") .WithMany("Statuses")
.HasForeignKey("MessageId") .HasForeignKey("MessageId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired() .IsRequired()
.HasConstraintName("fk_chat_statuses_chat_messages_message_id"); .HasConstraintName("fk_chat_read_receipts_chat_messages_message_id");
b.HasOne("DysonNetwork.Sphere.Chat.ChatMember", "Sender") b.HasOne("DysonNetwork.Sphere.Chat.ChatMember", "Sender")
.WithMany() .WithMany()
.HasForeignKey("SenderId") .HasForeignKey("SenderId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired() .IsRequired()
.HasConstraintName("fk_chat_statuses_chat_members_sender_id"); .HasConstraintName("fk_chat_read_receipts_chat_members_sender_id");
b.Navigation("Message"); b.Navigation("Message");

View File

@ -1,16 +1,12 @@
using System.Globalization; using System.Globalization;
using FFMpegCore; using FFMpegCore;
using System.Security.Cryptography; using System.Security.Cryptography;
using Blurhash.ImageSharp;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Minio; using Minio;
using Minio.DataModel.Args; using Minio.DataModel.Args;
using NodaTime; using NodaTime;
using Quartz; using Quartz;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using tusdotnet.Stores; using tusdotnet.Stores;
using ExifTag = SixLabors.ImageSharp.Metadata.Profiles.Exif.ExifTag;
namespace DysonNetwork.Sphere.Storage; namespace DysonNetwork.Sphere.Storage;
@ -53,32 +49,28 @@ public class FileService(
switch (contentType.Split('/')[0]) switch (contentType.Split('/')[0])
{ {
case "image": case "image":
stream.Position = 0; var blurhash = BlurHashSharp.SkiaSharp.BlurHashEncoder.Encode(xComponent: 3, yComponent: 3, stream);
// We still need ImageSharp for blurhash calculation
using (var imageSharp = await Image.LoadAsync<Rgba32>(stream))
{
var blurhash = Blurhasher.Encode(imageSharp, 3, 3);
// Reset stream position after ImageSharp read // Reset stream position after bitmap read
stream.Position = 0; stream.Position = 0;
// Use NetVips for the rest // Use NetVips for the rest
using var vipsImage = NetVips.Image.NewFromStream(stream); using (var vipsImage = NetVips.Image.NewFromStream(stream))
{
var width = vipsImage.Width; var width = vipsImage.Width;
var height = vipsImage.Height; var height = vipsImage.Height;
var format = vipsImage.Get("vips-loader") ?? "unknown"; var format = vipsImage.Get("vips-loader") ?? "unknown";
// Try to get orientation from exif data // Try to get orientation from exif data
ushort orientation = 1; ushort orientation = 1;
List<IExifValue> exif = []; Dictionary<string, object> exif = [];
// NetVips supports reading exif with vipsImage.GetField("exif-ifd0-Orientation") foreach (var field in vipsImage.GetFields())
// but we'll keep the ImageSharp exif handling for now {
var exifProfile = imageSharp.Metadata.ExifProfile; var value = vipsImage.Get(field);
if (exifProfile?.Values.FirstOrDefault(e => e.Tag == ExifTag.Orientation) exif.Add(field, value);
?.GetValue() is ushort o) if (field == "orientation") orientation = (ushort)value;
orientation = o; }
if (orientation is 6 or 8) if (orientation is 6 or 8)
(width, height) = (height, width); (width, height) = (height, width);