🗑️ Remove imagesharp
This commit is contained in:
parent
205ccd66b3
commit
b40282e43a
@ -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)
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
3386
DysonNetwork.Sphere/Migrations/20250518041519_OptimizeDataStructure.Designer.cs
generated
Normal file
3386
DysonNetwork.Sphere/Migrations/20250518041519_OptimizeDataStructure.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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");
|
||||||
|
|
||||||
|
@ -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":
|
||||||
|
var blurhash = BlurHashSharp.SkiaSharp.BlurHashEncoder.Encode(xComponent: 3, yComponent: 3, stream);
|
||||||
|
|
||||||
|
// Reset stream position after bitmap read
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
// We still need ImageSharp for blurhash calculation
|
|
||||||
using (var imageSharp = await Image.LoadAsync<Rgba32>(stream))
|
// Use NetVips for the rest
|
||||||
|
using (var vipsImage = NetVips.Image.NewFromStream(stream))
|
||||||
{
|
{
|
||||||
var blurhash = Blurhasher.Encode(imageSharp, 3, 3);
|
|
||||||
|
|
||||||
// Reset stream position after ImageSharp read
|
|
||||||
stream.Position = 0;
|
|
||||||
|
|
||||||
// Use NetVips for the rest
|
|
||||||
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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user