🐛 Fixes in CloudFile filemeta transfer via gRPC

This commit is contained in:
2025-07-19 12:03:18 +08:00
parent e0e1eb76cd
commit 4398984551
7 changed files with 73 additions and 52 deletions

View File

@@ -1,6 +1,9 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using DysonNetwork.Shared.Data; using DysonNetwork.Shared.Data;
using DysonNetwork.Shared.Proto;
using Google.Protobuf;
using Newtonsoft.Json;
using NodaTime; using NodaTime;
using NodaTime.Serialization.Protobuf; using NodaTime.Serialization.Protobuf;
@@ -103,7 +106,7 @@ public class CloudFile : ModelBase, ICloudFile, IIdentifiedResource
/// <returns>The protobuf message representation of this object</returns> /// <returns>The protobuf message representation of this object</returns>
public Shared.Proto.CloudFile ToProtoValue() public Shared.Proto.CloudFile ToProtoValue()
{ {
var protoFile = new Shared.Proto.CloudFile var proto = new Shared.Proto.CloudFile
{ {
Id = Id, Id = Id,
Name = Name ?? string.Empty, Name = Name ?? string.Empty,
@@ -113,28 +116,18 @@ public class CloudFile : ModelBase, ICloudFile, IIdentifiedResource
HasCompression = HasCompression, HasCompression = HasCompression,
Url = StorageUrl ?? string.Empty, Url = StorageUrl ?? string.Empty,
ContentType = MimeType ?? string.Empty, ContentType = MimeType ?? string.Empty,
UploadedAt = UploadedAt?.ToTimestamp() UploadedAt = UploadedAt?.ToTimestamp(),
// Convert file metadata
FileMeta = ByteString.CopyFromUtf8(
System.Text.Json.JsonSerializer.Serialize(FileMeta, GrpcTypeHelper.SystemTextSerializerOptions)
),
// Convert user metadata
UserMeta = ByteString.CopyFromUtf8(
System.Text.Json.JsonSerializer.Serialize(UserMeta, GrpcTypeHelper.SystemTextSerializerOptions)
)
}; };
// Convert FileMeta dictionary return proto;
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;
} }
} }

View File

@@ -1,5 +1,5 @@
using DysonNetwork.Shared.Proto; using DysonNetwork.Shared.Proto;
using Google.Protobuf.WellKnownTypes; using Google.Protobuf;
namespace DysonNetwork.Shared.Data; namespace DysonNetwork.Shared.Data;
@@ -41,10 +41,14 @@ public class CloudFileReferenceObject : ModelBase, ICloudFile
{ {
Id = proto.Id, Id = proto.Id,
Name = proto.Name, Name = proto.Name,
FileMeta = proto.FileMeta FileMeta = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object?>>(
.ToDictionary(kvp => kvp.Key, kvp => GrpcTypeHelper.ConvertValueToObject(kvp.Value)), proto.FileMeta.ToStringUtf8(),
UserMeta = proto.UserMeta GrpcTypeHelper.SystemTextSerializerOptions
.ToDictionary(kvp => kvp.Key, kvp => GrpcTypeHelper.ConvertValueToObject(kvp.Value)), ) ?? [],
UserMeta = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object?>>(
proto.UserMeta.ToStringUtf8(),
GrpcTypeHelper.SystemTextSerializerOptions
) ?? [],
MimeType = proto.MimeType, MimeType = proto.MimeType,
Hash = proto.Hash, Hash = proto.Hash,
Size = proto.Size, Size = proto.Size,
@@ -55,9 +59,9 @@ public class CloudFileReferenceObject : ModelBase, ICloudFile
/// <summary> /// <summary>
/// Converts the current object to its protobuf representation /// Converts the current object to its protobuf representation
/// </summary> /// </summary>
public Proto.CloudFile ToProtoValue() public CloudFile ToProtoValue()
{ {
var proto = new Proto.CloudFile var proto = new CloudFile
{ {
Id = Id, Id = Id,
Name = Name, Name = Name,
@@ -70,22 +74,14 @@ public class CloudFileReferenceObject : ModelBase, ICloudFile
}; };
// Convert file metadata // Convert file metadata
if (FileMeta != null) proto.FileMeta = ByteString.CopyFromUtf8(
{ System.Text.Json.JsonSerializer.Serialize(FileMeta, GrpcTypeHelper.SystemTextSerializerOptions)
foreach (var (key, value) in FileMeta) );
{
proto.FileMeta[key] = Value.ForString(value?.ToString() ?? string.Empty);
}
}
// Convert user metadata // Convert user metadata
if (UserMeta != null) proto.UserMeta = ByteString.CopyFromUtf8(
{ System.Text.Json.JsonSerializer.Serialize(UserMeta, GrpcTypeHelper.SystemTextSerializerOptions)
foreach (var (key, value) in UserMeta) );
{
proto.UserMeta[key] = Value.ForString(value?.ToString() ?? string.Empty);
}
}
return proto; return proto;
} }

View File

@@ -1,4 +1,5 @@
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization;
using Google.Protobuf.Collections; using Google.Protobuf.Collections;
using Google.Protobuf.WellKnownTypes; using Google.Protobuf.WellKnownTypes;
using Newtonsoft.Json; using Newtonsoft.Json;
@@ -8,7 +9,14 @@ namespace DysonNetwork.Shared.Proto;
public abstract class GrpcTypeHelper public abstract class GrpcTypeHelper
{ {
private static readonly JsonSerializerSettings SerializerSettings = new() public static readonly JsonSerializerOptions SystemTextSerializerOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
Converters = { new JsonStringEnumConverter() }
};
public static readonly JsonSerializerSettings SerializerSettings = new()
{ {
ContractResolver = new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy() }, ContractResolver = new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy() },
PreserveReferencesHandling = PreserveReferencesHandling.Objects, PreserveReferencesHandling = PreserveReferencesHandling.Objects,

View File

@@ -19,11 +19,11 @@ message CloudFile {
// Original name of the file // Original name of the file
string name = 2; string name = 2;
// The metadata uses JSON bytes to store to keep the data structure over gRPC
// File metadata (e.g., dimensions, duration, etc.) // File metadata (e.g., dimensions, duration, etc.)
map<string, google.protobuf.Value> file_meta = 3; bytes file_meta = 3;
// User-defined metadata // User-defined metadata
map<string, google.protobuf.Value> user_meta = 4; bytes user_meta = 4;
// MIME type of the file // MIME type of the file
string mime_type = 5; string mime_type = 5;

View File

@@ -1,6 +1,7 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using DysonNetwork.Pass.Account;
using DysonNetwork.Shared.Data; using DysonNetwork.Shared.Data;
using DysonNetwork.Sphere.Chat; using DysonNetwork.Sphere.Chat;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@@ -48,6 +49,7 @@ public class RealmMember : ModelBase
public Guid RealmId { get; set; } public Guid RealmId { get; set; }
public Realm Realm { get; set; } = null!; public Realm Realm { get; set; } = null!;
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
[NotMapped] public Account? Account { get; set; }
public int Role { get; set; } = RealmMemberRole.Normal; public int Role { get; set; } = RealmMemberRole.Normal;
public Instant? JoinedAt { get; set; } public Instant? JoinedAt { get; set; }

View File

@@ -62,7 +62,7 @@ public class RealmController(
.Include(e => e.Realm) .Include(e => e.Realm)
.ToListAsync(); .ToListAsync();
return members.ToList(); return await rs.LoadMemberAccounts(members);
} }
public class RealmMemberRequest public class RealmMemberRequest
@@ -256,7 +256,7 @@ public class RealmController(
// //
// var result = members.Skip(offset).Take(take).ToList(); // var result = members.Skip(offset).Take(take).ToList();
// //
// return Ok(result); // return Ok(await rs.LoadMemberAccounts(result));
// } // }
// else // else
// { // {
@@ -269,7 +269,7 @@ public class RealmController(
.Take(take) .Take(take)
.ToListAsync(); .ToListAsync();
return Ok(members); return Ok(await rs.LoadMemberAccounts(members));
// } // }
} }
@@ -287,7 +287,7 @@ public class RealmController(
.FirstOrDefaultAsync(); .FirstOrDefaultAsync();
if (member is null) return NotFound(); if (member is null) return NotFound();
return Ok(member); return Ok(await rs.LoadMemberAccount(member));
} }
[HttpDelete("{slug}/members/me")] [HttpDelete("{slug}/members/me")]

View File

@@ -1,5 +1,6 @@
using DysonNetwork.Shared; using DysonNetwork.Shared;
using DysonNetwork.Shared.Proto; using DysonNetwork.Shared.Proto;
using DysonNetwork.Shared.Registry;
using DysonNetwork.Sphere.Localization; using DysonNetwork.Sphere.Localization;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
@@ -10,7 +11,8 @@ public class RealmService(
AppDatabase db, AppDatabase db,
PusherService.PusherServiceClient pusher, PusherService.PusherServiceClient pusher,
AccountService.AccountServiceClient accounts, AccountService.AccountServiceClient accounts,
IStringLocalizer<NotificationResource> localizer IStringLocalizer<NotificationResource> localizer,
AccountClientHelper accountsHelper
) )
{ {
public async Task SendInviteNotify(RealmMember member) public async Task SendInviteNotify(RealmMember member)
@@ -44,4 +46,24 @@ public class RealmService(
.FirstOrDefaultAsync(m => m.RealmId == realmId && m.AccountId == accountId); .FirstOrDefaultAsync(m => m.RealmId == realmId && m.AccountId == accountId);
return member?.Role >= maxRequiredRole; return member?.Role >= maxRequiredRole;
} }
public async Task<RealmMember> LoadMemberAccount(RealmMember member)
{
var account = await accountsHelper.GetAccount(member.AccountId);
member.Account = Pass.Account.Account.FromProtoValue(account);
return member;
}
public async Task<List<RealmMember>> LoadMemberAccounts(ICollection<RealmMember> members)
{
var accountIds = members.Select(m => m.AccountId).ToList();
var accounts = (await accountsHelper.GetAccountBatch(accountIds)).ToDictionary(a => Guid.Parse(a.Id), a => a);
return members.Select(m =>
{
if (accounts.TryGetValue(m.AccountId, out var account))
m.Account = Pass.Account.Account.FromProtoValue(account);
return m;
}).ToList();
}
} }