♻️ Centralized data models (wip)

This commit is contained in:
2025-09-27 14:09:28 +08:00
parent 51b6f7309e
commit e70d8371f8
206 changed files with 1352 additions and 2128 deletions

View File

@@ -1,350 +0,0 @@
using DysonNetwork.Shared.Proto;
using NodaTime;
using NodaTime.Serialization.Protobuf;
namespace DysonNetwork.Shared.Data;
public class AccountReference : ModelBase
{
public Guid Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Nick { get; set; } = string.Empty;
public string Language { get; set; } = string.Empty;
public Instant? ActivatedAt { get; set; }
public bool IsSuperuser { get; set; }
public Guid? AutomatedId { get; set; }
public AccountProfileReference Profile { get; set; } = null!;
public List<AccountContactReference> Contacts { get; set; } = new();
public List<AccountBadgeReference> Badges { get; set; } = new();
public SubscriptionReference? PerkSubscription { get; set; }
public Proto.Account ToProtoValue()
{
var proto = new Proto.Account
{
Id = Id.ToString(),
Name = Name,
Nick = Nick,
Language = Language,
ActivatedAt = ActivatedAt?.ToTimestamp(),
IsSuperuser = IsSuperuser,
Profile = Profile.ToProtoValue(),
PerkSubscription = PerkSubscription?.ToProtoValue(),
CreatedAt = CreatedAt.ToTimestamp(),
UpdatedAt = UpdatedAt.ToTimestamp()
};
foreach (var contact in Contacts)
proto.Contacts.Add(contact.ToProtoValue());
foreach (var badge in Badges)
proto.Badges.Add(badge.ToProtoValue());
return proto;
}
public static AccountReference FromProtoValue(Proto.Account proto)
{
var account = new AccountReference
{
Id = Guid.Parse(proto.Id),
Name = proto.Name,
Nick = proto.Nick,
Language = proto.Language,
ActivatedAt = proto.ActivatedAt?.ToInstant(),
IsSuperuser = proto.IsSuperuser,
AutomatedId = string.IsNullOrEmpty(proto.AutomatedId) ? null : Guid.Parse(proto.AutomatedId),
PerkSubscription = proto.PerkSubscription != null
? SubscriptionReference.FromProtoValue(proto.PerkSubscription)
: null,
CreatedAt = proto.CreatedAt.ToInstant(),
UpdatedAt = proto.UpdatedAt.ToInstant()
};
account.Profile = AccountProfileReference.FromProtoValue(proto.Profile);
foreach (var contactProto in proto.Contacts)
account.Contacts.Add(AccountContactReference.FromProtoValue(contactProto));
foreach (var badgeProto in proto.Badges)
account.Badges.Add(AccountBadgeReference.FromProtoValue(badgeProto));
return account;
}
}
public class AccountProfileReference : ModelBase
{
public Guid Id { get; set; }
public string? FirstName { get; set; }
public string? MiddleName { get; set; }
public string? LastName { get; set; }
public string? Bio { get; set; }
public string? Gender { get; set; }
public string? Pronouns { get; set; }
public string? TimeZone { get; set; }
public string? Location { get; set; }
public List<ProfileLinkReference>? Links { get; set; }
public Instant? Birthday { get; set; }
public Instant? LastSeenAt { get; set; }
public VerificationMark? Verification { get; set; }
public int Experience { get; set; }
public int Level => Leveling.ExperiencePerLevel.Count(xp => Experience >= xp) - 1;
public double SocialCredits { get; set; } = 100;
public int SocialCreditsLevel => SocialCredits switch
{
< 100 => -1,
> 100 and < 200 => 0,
< 200 => 1,
_ => 2
};
public double LevelingProgress => Level >= Leveling.ExperiencePerLevel.Count - 1
? 100
: (Experience - Leveling.ExperiencePerLevel[Level]) * 100.0 /
(Leveling.ExperiencePerLevel[Level + 1] - Leveling.ExperiencePerLevel[Level]);
public CloudFileReferenceObject? Picture { get; set; }
public CloudFileReferenceObject? Background { get; set; }
public Guid AccountId { get; set; }
public Proto.AccountProfile ToProtoValue()
{
var proto = new Proto.AccountProfile
{
Id = Id.ToString(),
FirstName = FirstName ?? string.Empty,
MiddleName = MiddleName ?? string.Empty,
LastName = LastName ?? string.Empty,
Bio = Bio ?? string.Empty,
Gender = Gender ?? string.Empty,
Pronouns = Pronouns ?? string.Empty,
TimeZone = TimeZone ?? string.Empty,
Location = Location ?? string.Empty,
Birthday = Birthday?.ToTimestamp(),
LastSeenAt = LastSeenAt?.ToTimestamp(),
Experience = Experience,
Level = Level,
LevelingProgress = LevelingProgress,
SocialCredits = SocialCredits,
SocialCreditsLevel = SocialCreditsLevel,
Picture = Picture?.ToProtoValue(),
Background = Background?.ToProtoValue(),
AccountId = AccountId.ToString(),
Verification = Verification?.ToProtoValue(),
CreatedAt = CreatedAt.ToTimestamp(),
UpdatedAt = UpdatedAt.ToTimestamp()
};
return proto;
}
public static AccountProfileReference FromProtoValue(Proto.AccountProfile proto)
{
return new AccountProfileReference
{
Id = Guid.Parse(proto.Id),
FirstName = string.IsNullOrEmpty(proto.FirstName) ? null : proto.FirstName,
MiddleName = string.IsNullOrEmpty(proto.MiddleName) ? null : proto.MiddleName,
LastName = string.IsNullOrEmpty(proto.LastName) ? null : proto.LastName,
Bio = string.IsNullOrEmpty(proto.Bio) ? null : proto.Bio,
Gender = string.IsNullOrEmpty(proto.Gender) ? null : proto.Gender,
Pronouns = string.IsNullOrEmpty(proto.Pronouns) ? null : proto.Pronouns,
TimeZone = string.IsNullOrEmpty(proto.TimeZone) ? null : proto.TimeZone,
Location = string.IsNullOrEmpty(proto.Location) ? null : proto.Location,
Birthday = proto.Birthday?.ToInstant(),
LastSeenAt = proto.LastSeenAt?.ToInstant(),
Experience = proto.Experience,
SocialCredits = proto.SocialCredits,
Picture = proto.Picture != null ? CloudFileReferenceObject.FromProtoValue(proto.Picture) : null,
Background = proto.Background != null ? CloudFileReferenceObject.FromProtoValue(proto.Background) : null,
AccountId = Guid.Parse(proto.AccountId),
Verification = proto.Verification != null ? VerificationMark.FromProtoValue(proto.Verification) : null,
CreatedAt = proto.CreatedAt.ToInstant(),
UpdatedAt = proto.UpdatedAt.ToInstant()
};
}
}
public class AccountContactReference : ModelBase
{
public Guid Id { get; set; }
public AccountContactReferenceType Type { get; set; }
public Instant? VerifiedAt { get; set; }
public bool IsPrimary { get; set; } = false;
public bool IsPublic { get; set; } = false;
public string Content { get; set; } = string.Empty;
public Guid AccountId { get; set; }
public Shared.Proto.AccountContact ToProtoValue()
{
var proto = new Shared.Proto.AccountContact
{
Id = Id.ToString(),
Type = Type switch
{
AccountContactReferenceType.Email => Shared.Proto.AccountContactType.Email,
AccountContactReferenceType.PhoneNumber => Shared.Proto.AccountContactType.PhoneNumber,
AccountContactReferenceType.Address => Shared.Proto.AccountContactType.Address,
_ => Shared.Proto.AccountContactType.Unspecified
},
Content = Content,
IsPrimary = IsPrimary,
VerifiedAt = VerifiedAt?.ToTimestamp(),
AccountId = AccountId.ToString(),
CreatedAt = CreatedAt.ToTimestamp(),
UpdatedAt = UpdatedAt.ToTimestamp()
};
return proto;
}
public static AccountContactReference FromProtoValue(Shared.Proto.AccountContact proto)
{
var contact = new AccountContactReference
{
Id = Guid.Parse(proto.Id),
AccountId = Guid.Parse(proto.AccountId),
Type = proto.Type switch
{
Shared.Proto.AccountContactType.Email => AccountContactReferenceType.Email,
Shared.Proto.AccountContactType.PhoneNumber => AccountContactReferenceType.PhoneNumber,
Shared.Proto.AccountContactType.Address => AccountContactReferenceType.Address,
_ => AccountContactReferenceType.Email
},
Content = proto.Content,
IsPrimary = proto.IsPrimary,
VerifiedAt = proto.VerifiedAt?.ToInstant(),
CreatedAt = proto.CreatedAt.ToInstant(),
UpdatedAt = proto.UpdatedAt.ToInstant()
};
return contact;
}
}
public enum AccountContactReferenceType
{
Email,
PhoneNumber,
Address
}
public class AccountBadgeReference : ModelBase
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Type { get; set; } = null!;
public string? Label { get; set; }
public string? Caption { get; set; }
public Dictionary<string, object?> Meta { get; set; } = new();
public Instant? ActivatedAt { get; set; }
public Instant? ExpiredAt { get; set; }
public Guid AccountId { get; set; }
public AccountBadge ToProtoValue()
{
var proto = new AccountBadge
{
Id = Id.ToString(),
Type = Type,
Label = Label ?? string.Empty,
Caption = Caption ?? string.Empty,
ActivatedAt = ActivatedAt?.ToTimestamp(),
ExpiredAt = ExpiredAt?.ToTimestamp(),
AccountId = AccountId.ToString(),
CreatedAt = CreatedAt.ToTimestamp(),
UpdatedAt = UpdatedAt.ToTimestamp()
};
proto.Meta.Add(GrpcTypeHelper.ConvertToValueMap(Meta));
return proto;
}
public static AccountBadgeReference FromProtoValue(AccountBadge proto)
{
var badge = new AccountBadgeReference
{
Id = Guid.Parse(proto.Id),
AccountId = Guid.Parse(proto.AccountId),
Type = proto.Type,
Label = proto.Label,
Caption = proto.Caption,
ActivatedAt = proto.ActivatedAt?.ToInstant(),
ExpiredAt = proto.ExpiredAt?.ToInstant(),
CreatedAt = proto.CreatedAt.ToInstant(),
UpdatedAt = proto.UpdatedAt.ToInstant()
};
return badge;
}
}
public class ProfileLinkReference
{
public string Name { get; set; } = string.Empty;
public string Url { get; set; } = string.Empty;
}
public static class Leveling
{
public static readonly List<int> ExperiencePerLevel =
[
0, // Level 0
100, // Level 1
250, // Level 2
500, // Level 3
1000, // Level 4
2000, // Level 5
4000, // Level 6
8000, // Level 7
16000, // Level 8
32000, // Level 9
64000, // Level 10
128000, // Level 11
256000, // Level 12
512000, // Level 13
1024000
];
}
public class ApiKeyReference : ModelBase
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Label { get; set; } = null!;
public Guid AccountId { get; set; }
public Guid SessionId { get; set; }
public string? Key { get; set; }
public ApiKey ToProtoValue()
{
return new ApiKey
{
Id = Id.ToString(),
Label = Label,
AccountId = AccountId.ToString(),
SessionId = SessionId.ToString(),
Key = Key,
CreatedAt = CreatedAt.ToTimestamp(),
UpdatedAt = UpdatedAt.ToTimestamp()
};
}
public static ApiKeyReference FromProtoValue(ApiKey proto)
{
return new ApiKeyReference
{
Id = Guid.Parse(proto.Id),
AccountId = Guid.Parse(proto.AccountId),
SessionId = Guid.Parse(proto.SessionId),
Label = proto.Label,
Key = proto.Key,
CreatedAt = proto.CreatedAt.ToInstant(),
UpdatedAt = proto.UpdatedAt.ToInstant()
};
}
}

View File

@@ -1,58 +0,0 @@
using DysonNetwork.Shared.Proto;
using NodaTime;
using NodaTime.Serialization.Protobuf;
namespace DysonNetwork.Shared.Data;
public class AccountStatusReference : ModelBase
{
public Guid Id { get; set; } = Guid.NewGuid();
public StatusAttitude Attitude { get; set; }
public bool IsOnline { get; set; }
public bool IsCustomized { get; set; } = true;
public bool IsInvisible { get; set; }
public bool IsNotDisturb { get; set; }
public string? Label { get; set; }
public Dictionary<string, object>? Meta { get; set; }
public Instant? ClearedAt { get; set; }
public Guid AccountId { get; set; }
public AccountStatus ToProtoValue()
{
var proto = new AccountStatus
{
Id = Id.ToString(),
Attitude = Attitude,
IsOnline = IsOnline,
IsCustomized = IsCustomized,
IsInvisible = IsInvisible,
IsNotDisturb = IsNotDisturb,
Label = Label ?? string.Empty,
Meta = GrpcTypeHelper.ConvertObjectToByteString(Meta),
ClearedAt = ClearedAt?.ToTimestamp(),
AccountId = AccountId.ToString()
};
return proto;
}
public static AccountStatusReference FromProtoValue(AccountStatus proto)
{
var status = new AccountStatusReference
{
Id = Guid.Parse(proto.Id),
Attitude = proto.Attitude,
IsOnline = proto.IsOnline,
IsCustomized = proto.IsCustomized,
IsInvisible = proto.IsInvisible,
IsNotDisturb = proto.IsNotDisturb,
Label = proto.Label,
Meta = GrpcTypeHelper.ConvertByteStringToObject<Dictionary<string, object>>(proto.Meta),
ClearedAt = proto.ClearedAt?.ToInstant(),
AccountId = Guid.Parse(proto.AccountId)
};
return status;
}
}

View File

@@ -1,42 +0,0 @@
namespace DysonNetwork.Shared.Data;
public abstract class ActionLogType
{
public const string NewLogin = "login";
public const string ChallengeAttempt = "challenges.attempt";
public const string ChallengeSuccess = "challenges.success";
public const string ChallengeFailure = "challenges.failure";
public const string PostCreate = "posts.create";
public const string PostUpdate = "posts.update";
public const string PostDelete = "posts.delete";
public const string PostReact = "posts.react";
public const string PostPin = "posts.pin";
public const string PostUnpin = "posts.unpin";
public const string MessageCreate = "messages.create";
public const string MessageUpdate = "messages.update";
public const string MessageDelete = "messages.delete";
public const string MessageReact = "messages.react";
public const string PublisherCreate = "publishers.create";
public const string PublisherUpdate = "publishers.update";
public const string PublisherDelete = "publishers.delete";
public const string PublisherMemberInvite = "publishers.members.invite";
public const string PublisherMemberJoin = "publishers.members.join";
public const string PublisherMemberLeave = "publishers.members.leave";
public const string PublisherMemberKick = "publishers.members.kick";
public const string RealmCreate = "realms.create";
public const string RealmUpdate = "realms.update";
public const string RealmDelete = "realms.delete";
public const string RealmInvite = "realms.invite";
public const string RealmJoin = "realms.join";
public const string RealmLeave = "realms.leave";
public const string RealmKick = "realms.kick";
public const string RealmAdjustRole = "realms.role.edit";
public const string ChatroomCreate = "chatrooms.create";
public const string ChatroomUpdate = "chatrooms.update";
public const string ChatroomDelete = "chatrooms.delete";
public const string ChatroomInvite = "chatrooms.invite";
public const string ChatroomJoin = "chatrooms.join";
public const string ChatroomLeave = "chatrooms.leave";
public const string ChatroomKick = "chatrooms.kick";
public const string ChatroomAdjustRole = "chatrooms.role.edit";
}

View File

@@ -1,83 +0,0 @@
using DysonNetwork.Shared.Proto;
namespace DysonNetwork.Shared.Data;
public enum ContentSensitiveMark
{
Language,
SexualContent,
Violence,
Profanity,
HateSpeech,
Racism,
AdultContent,
DrugAbuse,
AlcoholAbuse,
Gambling,
SelfHarm,
ChildAbuse,
Other
}
/// <summary>
/// The class that used in jsonb columns which referenced the cloud file.
/// The aim of this class is to store some properties that won't change to a file to reduce the database load.
/// </summary>
public class CloudFileReferenceObject : ModelBase, ICloudFile
{
public string Id { get; set; } = null!;
public string Name { get; set; } = string.Empty;
public Dictionary<string, object?> FileMeta { get; set; } = null!;
public Dictionary<string, object?> UserMeta { get; set; } = null!;
public List<ContentSensitiveMark>? SensitiveMarks { get; set; }
public string? MimeType { get; set; }
public string? Hash { get; set; }
public long Size { get; set; }
public bool HasCompression { get; set; } = false;
public static CloudFileReferenceObject FromProtoValue(Proto.CloudFile proto)
{
return new CloudFileReferenceObject
{
Id = proto.Id,
Name = proto.Name,
FileMeta = GrpcTypeHelper.ConvertByteStringToObject<Dictionary<string, object?>>(proto.FileMeta) ?? [],
UserMeta = GrpcTypeHelper.ConvertByteStringToObject<Dictionary<string, object?>>(proto.UserMeta) ?? [],
SensitiveMarks = proto.HasSensitiveMarks
? GrpcTypeHelper.ConvertByteStringToObject<List<ContentSensitiveMark>>(proto.SensitiveMarks)
: [],
MimeType = proto.MimeType,
Hash = proto.Hash,
Size = proto.Size,
HasCompression = proto.HasCompression
};
}
/// <summary>
/// Converts the current object to its protobuf representation
/// </summary>
public CloudFile ToProtoValue()
{
var proto = new CloudFile
{
Id = Id,
Name = Name,
MimeType = MimeType ?? string.Empty,
Hash = Hash ?? string.Empty,
Size = Size,
HasCompression = HasCompression,
ContentType = MimeType ?? string.Empty,
Url = string.Empty // This should be set by the caller if needed
};
// Convert file metadata
proto.FileMeta = GrpcTypeHelper.ConvertObjectToByteString(FileMeta);
// Convert user metadata
proto.UserMeta = GrpcTypeHelper.ConvertObjectToByteString(UserMeta);
proto.SensitiveMarks = GrpcTypeHelper.ConvertObjectToByteString(SensitiveMarks);
return proto;
}
}

View File

@@ -1,55 +0,0 @@
using NodaTime;
namespace DysonNetwork.Shared.Data;
/// <summary>
/// Common interface for cloud file entities that can be used in file operations.
/// This interface exposes the essential properties needed for file operations
/// and is implemented by both CloudFile and CloudFileReferenceObject.
/// </summary>
public interface ICloudFile
{
public Instant CreatedAt { get; }
public Instant UpdatedAt { get; }
public Instant? DeletedAt { get; }
/// <summary>
/// Gets the unique identifier of the cloud file.
/// </summary>
string Id { get; }
/// <summary>
/// Gets the name of the cloud file.
/// </summary>
string Name { get; }
/// <summary>
/// Gets the file metadata dictionary.
/// </summary>
Dictionary<string, object?> FileMeta { get; }
/// <summary>
/// Gets the user metadata dictionary.
/// </summary>
Dictionary<string, object>? UserMeta { get; }
/// <summary>
/// Gets the MIME type of the file.
/// </summary>
string? MimeType { get; }
/// <summary>
/// Gets the hash of the file content.
/// </summary>
string? Hash { get; }
/// <summary>
/// Gets the size of the file in bytes.
/// </summary>
long Size { get; }
/// <summary>
/// Gets whether the file has a compressed version available.
/// </summary>
bool HasCompression { get; }
}

View File

@@ -1,15 +0,0 @@
using NodaTime;
namespace DysonNetwork.Shared.Data;
public interface IIdentifiedResource
{
public string ResourceIdentifier { get; }
}
public abstract class ModelBase
{
public Instant CreatedAt { get; set; }
public Instant UpdatedAt { get; set; }
public Instant? DeletedAt { get; set; }
}

View File

@@ -1,71 +0,0 @@
using NodaTime;
using NodaTime.Serialization.Protobuf;
namespace DysonNetwork.Shared.Data;
public class SubscriptionReference : ModelBase
{
public Guid Id { get; set; }
public string Identifier { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public bool IsActive { get; set; }
public bool IsAvailable { get; set; }
public Instant BegunAt { get; set; }
public Instant? EndedAt { get; set; }
public Instant? RenewalAt { get; set; }
public SubscriptionReferenceStatus Status { get; set; }
public Guid AccountId { get; set; }
public static SubscriptionReference FromProtoValue(Proto.SubscriptionReferenceObject proto)
{
return new SubscriptionReference
{
Id = Guid.Parse(proto.Id),
Identifier = proto.Identifier,
DisplayName = proto.DisplayName,
IsActive = proto.IsActive,
IsAvailable = proto.IsAvailable,
BegunAt = proto.BegunAt.ToInstant(),
EndedAt = proto.EndedAt?.ToInstant(),
RenewalAt = proto.RenewalAt?.ToInstant(),
Status = (SubscriptionReferenceStatus)proto.Status,
AccountId = Guid.Parse(proto.AccountId),
CreatedAt = proto.CreatedAt.ToInstant(),
UpdatedAt = proto.UpdatedAt.ToInstant(),
};
}
public Proto.SubscriptionReferenceObject ToProtoValue()
{
return new Proto.SubscriptionReferenceObject
{
Id = Id.ToString(),
Identifier = Identifier,
DisplayName = DisplayName,
IsActive = IsActive,
IsAvailable = IsAvailable,
BegunAt = BegunAt.ToTimestamp(),
EndedAt = EndedAt?.ToTimestamp(),
RenewalAt = RenewalAt?.ToTimestamp(),
AccountId = AccountId.ToString(),
CreatedAt = CreatedAt.ToTimestamp(),
UpdatedAt = UpdatedAt.ToTimestamp(),
Status = Status switch
{
SubscriptionReferenceStatus.Unpaid => Proto.SubscriptionStatus.Unpaid,
SubscriptionReferenceStatus.Active => Proto.SubscriptionStatus.Active,
SubscriptionReferenceStatus.Expired => Proto.SubscriptionStatus.Expired,
SubscriptionReferenceStatus.Cancelled => Proto.SubscriptionStatus.Cancelled,
_ => Proto.SubscriptionStatus.Unpaid
}
};
}
}
public enum SubscriptionReferenceStatus
{
Unpaid = 0,
Active = 1,
Expired = 2,
Cancelled = 3
}

View File

@@ -1,72 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace DysonNetwork.Shared.Data;
/// <summary>
/// The verification info of a resource
/// stands, for it is really an individual or organization or a company in the real world.
/// Besides, it can also be use for mark parody or fake.
/// </summary>
public class VerificationMark
{
public VerificationMarkType Type { get; set; }
[MaxLength(1024)] public string? Title { get; set; }
[MaxLength(8192)] public string? Description { get; set; }
[MaxLength(1024)] public string? VerifiedBy { get; set; }
public Proto.VerificationMark ToProtoValue()
{
var proto = new Proto.VerificationMark
{
Type = Type switch
{
VerificationMarkType.Official => Proto.VerificationMarkType.Official,
VerificationMarkType.Individual => Proto.VerificationMarkType.Individual,
VerificationMarkType.Organization => Proto.VerificationMarkType.Organization,
VerificationMarkType.Government => Proto.VerificationMarkType.Government,
VerificationMarkType.Creator => Proto.VerificationMarkType.Creator,
VerificationMarkType.Developer => Proto.VerificationMarkType.Developer,
VerificationMarkType.Parody => Proto.VerificationMarkType.Parody,
_ => Proto.VerificationMarkType.Unspecified
},
Title = Title ?? string.Empty,
Description = Description ?? string.Empty,
VerifiedBy = VerifiedBy ?? string.Empty
};
return proto;
}
public static VerificationMark FromProtoValue(Shared.Proto.VerificationMark proto)
{
return new VerificationMark
{
Type = proto.Type switch
{
Proto.VerificationMarkType.Official => VerificationMarkType.Official,
Proto.VerificationMarkType.Individual => VerificationMarkType.Individual,
Proto.VerificationMarkType.Organization => VerificationMarkType.Organization,
Proto.VerificationMarkType.Government => VerificationMarkType.Government,
Proto.VerificationMarkType.Creator => VerificationMarkType.Creator,
Proto.VerificationMarkType.Developer => VerificationMarkType.Developer,
Proto.VerificationMarkType.Parody => VerificationMarkType.Parody,
_ => VerificationMarkType.Individual
},
Title = proto.Title,
Description = proto.Description,
VerifiedBy = proto.VerifiedBy
};
}
}
public enum VerificationMarkType
{
Official,
Individual,
Organization,
Government,
Creator,
Developer,
Parody
}

View File

@@ -1,13 +0,0 @@
namespace DysonNetwork.Shared.Data;
public abstract class WebSocketPacketType
{
public const string Ping = "ping";
public const string Pong = "pong";
public const string Error = "error";
public const string MessageNew = "messages.new";
public const string MessageUpdate = "messages.update";
public const string MessageDelete = "messages.delete";
public const string CallParticipantsUpdate = "call.participants.update";
}

View File

@@ -1,79 +0,0 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using DysonNetwork.Shared.Proto;
using NodaTime;
using NodaTime.Serialization.SystemTextJson;
namespace DysonNetwork.Shared.Data;
public class WebSocketPacket
{
public string Type { get; set; } = null!;
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public object? Data { get; set; } = null!;
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Endpoint { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? ErrorMessage { get; set; }
/// <summary>
/// Creates a WebSocketPacket from raw WebSocket message bytes
/// </summary>
/// <param name="bytes">Raw WebSocket message bytes</param>
/// <returns>Deserialized WebSocketPacket</returns>
public static WebSocketPacket FromBytes(byte[] bytes)
{
var json = System.Text.Encoding.UTF8.GetString(bytes);
return JsonSerializer.Deserialize<WebSocketPacket>(json, GrpcTypeHelper.SerializerOptions) ??
throw new JsonException("Failed to deserialize WebSocketPacket");
}
/// <summary>
/// Deserializes the Data property to the specified type T
/// </summary>
/// <typeparam name="T">Target type to deserialize to</typeparam>
/// <returns>Deserialized data of type T</returns>
public T? GetData<T>()
{
if (Data is T typedData)
return typedData;
return JsonSerializer.Deserialize<T>(
JsonSerializer.Serialize(Data, GrpcTypeHelper.SerializerOptions),
GrpcTypeHelper.SerializerOptions
);
}
/// <summary>
/// Serializes this WebSocketPacket to a byte array for sending over WebSocket
/// </summary>
/// <returns>Byte array representation of the packet</returns>
public byte[] ToBytes()
{
var json = JsonSerializer.Serialize(this, GrpcTypeHelper.SerializerOptions);
return System.Text.Encoding.UTF8.GetBytes(json);
}
public Shared.Proto.WebSocketPacket ToProtoValue()
{
return new Shared.Proto.WebSocketPacket
{
Type = Type,
Data = GrpcTypeHelper.ConvertObjectToByteString(Data),
ErrorMessage = ErrorMessage
};
}
public static WebSocketPacket FromProtoValue(Shared.Proto.WebSocketPacket packet)
{
return new WebSocketPacket
{
Type = packet.Type,
Data = GrpcTypeHelper.ConvertByteStringToObject<object?>(packet.Data),
ErrorMessage = packet.ErrorMessage
};
}
}