From 2bd12d87090470d3c96ddbab0af43feb5a2a098c Mon Sep 17 00:00:00 2001 From: Aram Date: Sun, 27 Oct 2024 22:38:12 +0400 Subject: [PATCH 1/9] Enhance serialization in UserStorage --- src/Argon.Api/Argon.Api.csproj | 4 ++ .../Grains.Persistence.States/UserStorage.cs | 43 ++++++++++++++++--- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/Argon.Api/Argon.Api.csproj b/src/Argon.Api/Argon.Api.csproj index e1d0b5d3..cfcf0e9e 100644 --- a/src/Argon.Api/Argon.Api.csproj +++ b/src/Argon.Api/Argon.Api.csproj @@ -11,6 +11,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Argon.Api/Grains.Persistence.States/UserStorage.cs b/src/Argon.Api/Grains.Persistence.States/UserStorage.cs index 09637aea..0f8eb863 100644 --- a/src/Argon.Api/Grains.Persistence.States/UserStorage.cs +++ b/src/Argon.Api/Grains.Persistence.States/UserStorage.cs @@ -1,6 +1,8 @@ namespace Argon.Api.Grains.Persistence.States; +using System.Runtime.Serialization; using MemoryPack; +using MessagePack; [GenerateSerializer] [Serializable] @@ -8,12 +10,41 @@ namespace Argon.Api.Grains.Persistence.States; [Alias(nameof(UserStorage))] public sealed partial record UserStorage { - [Id(0)] public Guid Id { get; set; } = Guid.Empty; - [Id(1)] public string Username { get; set; } = string.Empty; - [Id(2)] public string Password { get; set; } = string.Empty; - [Id(5)] public string AvatarUrl { get; set; } = string.Empty; - [Id(3)] public DateTime CreatedAt { get; } = DateTime.UtcNow; - [Id(4)] public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; + [property: DataMember(Order = 0)] + [property: MemoryPackOrder(0)] + [property: Key(0)] + [Id(0)] + public Guid Id { get; set; } = Guid.Empty; + + [property: DataMember(Order = 1)] + [property: MemoryPackOrder(1)] + [property: Key(1)] + [Id(1)] + public string Username { get; set; } = string.Empty; + + [property: DataMember(Order = 2)] + [property: MemoryPackOrder(2)] + [property: Key(2)] + [Id(2)] + public string Password { get; set; } = string.Empty; + + [property: DataMember(Order = 5)] + [property: MemoryPackOrder(5)] + [property: Key(5)] + [Id(5)] + public string AvatarUrl { get; set; } = string.Empty; + + [property: DataMember(Order = 3)] + [property: MemoryPackOrder(3)] + [property: Key(3)] + [Id(3)] + public DateTime CreatedAt { get; } = DateTime.UtcNow; + + [property: DataMember(Order = 4)] + [property: MemoryPackOrder(4)] + [property: Key(4)] + [Id(4)] + public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; public static implicit operator UserStorageDto(UserStorage userStorage) { From 684548f19cb084337a4bb57706f876095e66af5c Mon Sep 17 00:00:00 2001 From: Aram Date: Sun, 27 Oct 2024 23:52:15 +0400 Subject: [PATCH 2/9] Rename method Authenticate to Authorize in UserManager --- src/Argon.Api/Controllers/UsersController.cs | 2 +- .../Grains.Interfaces/IUserManager.cs | 2 +- src/Argon.Api/Grains/UserManager.cs | 2 +- src/Argon.Api/Services/UserAuthorization.cs | 6 ++-- src/Argon.Contracts/IUserAuthorization.cs | 35 +++++++++++-------- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/Argon.Api/Controllers/UsersController.cs b/src/Argon.Api/Controllers/UsersController.cs index 4c0abbb0..9c2e35f9 100644 --- a/src/Argon.Api/Controllers/UsersController.cs +++ b/src/Argon.Api/Controllers/UsersController.cs @@ -28,7 +28,7 @@ public async Task> Post([FromBody] UserInputDto dto public async Task> Authenticate([FromBody] UserInputDto dto) { var userManager = grainFactory.GetGrain(dto.Username); - var token = await userManager.Authenticate(dto.Password); + var token = await userManager.Authorize(dto.Password); return token; } diff --git a/src/Argon.Api/Grains.Interfaces/IUserManager.cs b/src/Argon.Api/Grains.Interfaces/IUserManager.cs index 59991259..c2b54948 100644 --- a/src/Argon.Api/Grains.Interfaces/IUserManager.cs +++ b/src/Argon.Api/Grains.Interfaces/IUserManager.cs @@ -12,7 +12,7 @@ public interface IUserManager : IGrainWithStringKey Task Get(); [Alias("Authenticate")] - Task Authenticate(string password); + Task Authorize(string password); [Alias("CreateServer")] Task CreateServer(string name, string description); diff --git a/src/Argon.Api/Grains/UserManager.cs b/src/Argon.Api/Grains/UserManager.cs index 6193ded6..0ec76647 100644 --- a/src/Argon.Api/Grains/UserManager.cs +++ b/src/Argon.Api/Grains/UserManager.cs @@ -36,7 +36,7 @@ public async Task Get() return userStore.State; } - public Task Authenticate(string password) + public Task Authorize(string password) { var match = userStore.State.Password == HashPassword(password); diff --git a/src/Argon.Api/Services/UserAuthorization.cs b/src/Argon.Api/Services/UserAuthorization.cs index 03aac0ba..26141e82 100644 --- a/src/Argon.Api/Services/UserAuthorization.cs +++ b/src/Argon.Api/Services/UserAuthorization.cs @@ -1,14 +1,14 @@ namespace Argon.Api.Services; -using Grains.Interfaces; using Contracts; +using Grains.Interfaces; public class UserAuthorization(IGrainFactory grainFactory) : IUserAuthorization { public async Task AuthorizeAsync(AuthorizeRequest request) { // TODO machineKey - var token = await grainFactory.GetGrain(request.username).Authenticate(request.password); - return new AuthorizeResponse(token, [new ServerResponse(Guid.NewGuid(), "xuita", null)]); + var token = await grainFactory.GetGrain(request.username).Authorize(request.password); + return new AuthorizeResponse(token); } } \ No newline at end of file diff --git a/src/Argon.Contracts/IUserAuthorization.cs b/src/Argon.Contracts/IUserAuthorization.cs index abcda690..0404cf4d 100644 --- a/src/Argon.Contracts/IUserAuthorization.cs +++ b/src/Argon.Contracts/IUserAuthorization.cs @@ -1,7 +1,6 @@ namespace Argon.Contracts; using System.Runtime.Serialization; -using ActualLab.Fusion; using ActualLab.Rpc; using MemoryPack; using MessagePack; @@ -11,19 +10,25 @@ public interface IUserAuthorization : IRpcService Task AuthorizeAsync(AuthorizeRequest request); } -[DataContract, MemoryPackable(GenerateType.VersionTolerant), MessagePackObject] +[DataContract] +[MemoryPackable(GenerateType.VersionTolerant)] +[MessagePackObject] public sealed partial record AuthorizeRequest( - [property: DataMember(Order = 0), MemoryPackOrder(0), Key(0)] string username, - [property: DataMember(Order = 1), MemoryPackOrder(1), Key(1)] string password, - [property: DataMember(Order = 2), MemoryPackOrder(2), Key(2)] string machineKey); + [property: DataMember(Order = 0)] + [property: MemoryPackOrder(0)] + [property: Key(0)] + string username, + [property: DataMember(Order = 1)] + [property: MemoryPackOrder(1)] + [property: Key(1)] + string password, + [property: DataMember(Order = 2)] + [property: MemoryPackOrder(2)] + [property: Key(2)] + string machineKey); - -public sealed partial record ServerResponse( - [property: DataMember(Order = 0), MemoryPackOrder(0), Key(0)] Guid serverId, - [property: DataMember(Order = 1), MemoryPackOrder(1), Key(1)] string serverName, - [property: DataMember(Order = 2), MemoryPackOrder(2), Key(2)] string? avatarFileId -); - -public sealed partial record AuthorizeResponse( - [property: DataMember(Order = 0), MemoryPackOrder(0), Key(0)] string token, - [property: DataMember(Order = 1), MemoryPackOrder(1), Key(1)] List servers); \ No newline at end of file +public sealed record AuthorizeResponse( + [property: DataMember(Order = 0)] + [property: MemoryPackOrder(0)] + [property: Key(0)] + string token); \ No newline at end of file From 32a1ce65d6f366e9ce34c9aa498c119250ecf9b3 Mon Sep 17 00:00:00 2001 From: Aram Date: Sun, 27 Oct 2024 23:52:25 +0400 Subject: [PATCH 3/9] Add IUserInteraction interface and related data contracts --- src/Argon.Contracts/IUserInteraction.cs | 71 +++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Argon.Contracts/IUserInteraction.cs diff --git a/src/Argon.Contracts/IUserInteraction.cs b/src/Argon.Contracts/IUserInteraction.cs new file mode 100644 index 00000000..98363e98 --- /dev/null +++ b/src/Argon.Contracts/IUserInteraction.cs @@ -0,0 +1,71 @@ +namespace Argon.Contracts; + +using System.Runtime.Serialization; +using ActualLab.Rpc; +using MemoryPack; +using MessagePack; + +public interface IUserInteraction : IRpcService +{ + Task GetMe(string username); + Task CreateServer(string username, CreateServerRequest request); + Task> GetServers(string username); + + Task> GetServerDetails(string username); + + // Task CreateChannel(string username); + Task JoinChannel(string username, ChannelJoinRequest request); +} + +[DataContract, MemoryPackable(GenerateType.VersionTolerant), MessagePackObject] +public sealed partial record UserResponse( + [property: DataMember(Order = 0), MemoryPackOrder(0), Key(0)] Guid Id, + [property: DataMember(Order = 1), MemoryPackOrder(1), Key(1)] string Username, + [property: DataMember(Order = 2), MemoryPackOrder(2), Key(2)] string AvatarUrl, + [property: DataMember(Order = 3), MemoryPackOrder(3), Key(3)] DateTime CreatedAt, + [property: DataMember(Order = 4), MemoryPackOrder(4), Key(4)] DateTime UpdatedAt +); + +[DataContract, MemoryPackable(GenerateType.VersionTolerant), MessagePackObject] +public sealed partial record CreateServerRequest( + [property: DataMember(Order = 0), MemoryPackOrder(0), Key(0)] string Name, + [property: DataMember(Order = 1), MemoryPackOrder(1), Key(1)] string Description, + [property: DataMember(Order = 2), MemoryPackOrder(2), Key(2)] string AvatarUrl + ); + +[DataContract, MemoryPackable(GenerateType.VersionTolerant), MessagePackObject] +public sealed partial record ServerResponse( + [property: DataMember(Order = 0), MemoryPackOrder(0), Key(0)] Guid Id, + [property: DataMember(Order = 1), MemoryPackOrder(1), Key(1)] string Name, + [property: DataMember(Order = 2), MemoryPackOrder(2), Key(2)] string Description, + [property: DataMember(Order = 3), MemoryPackOrder(3), Key(3)] string AvatarUrl, + [property: DataMember(Order = 4), MemoryPackOrder(4), Key(4)] List Channels, + [property: DataMember(Order = 5), MemoryPackOrder(5), Key(5)] DateTime CreatedAt, + [property: DataMember(Order = 6), MemoryPackOrder(6), Key(6)] DateTime UpdatedAt + // TODO: all users of the server with their statuses(online/offline/in channel) + ); + +[DataContract, MemoryPackable(GenerateType.VersionTolerant), MessagePackObject] +public sealed partial record ServerDetailsResponse( + [property: DataMember(Order = 0), MemoryPackOrder(0), Key(0)] Guid Id, + [property: DataMember(Order = 1), MemoryPackOrder(1), Key(1)] string Name, + [property: DataMember(Order = 2), MemoryPackOrder(2), Key(2)] string Description, + [property: DataMember(Order = 3), MemoryPackOrder(3), Key(3)] string CreatedBy, + [property: DataMember(Order = 4), MemoryPackOrder(4), Key(4)] string ChannelType, + [property: DataMember(Order = 5), MemoryPackOrder(5), Key(5)] string AccessLevel, + [property: DataMember(Order = 6), MemoryPackOrder(6), Key(6)] DateTime CreatedAt, + [property: DataMember(Order = 7), MemoryPackOrder(7), Key(7)] DateTime UpdatedAt + // TODO: all users currently connected to this channel + ); + +[DataContract, MemoryPackable(GenerateType.VersionTolerant), MessagePackObject] +public sealed partial record ChannelJoinRequest( + [property: DataMember(Order = 0), MemoryPackOrder(0), Key(0)] Guid ServerId, + [property: DataMember(Order = 1), MemoryPackOrder(1), Key(1)] Guid ChannelId + ); + +[DataContract, MemoryPackable(GenerateType.VersionTolerant), MessagePackObject] +public sealed partial record ChannelJoinResponse( + [property: DataMember(Order = 0), MemoryPackOrder(0), Key(0)] string Token + ); + From 4049e9ff78cdd8fe3559d3fc1839088e09f9b650 Mon Sep 17 00:00:00 2001 From: Aram Date: Sun, 27 Oct 2024 23:57:22 +0400 Subject: [PATCH 4/9] Refactor user interaction interfaces --- src/Argon.Contracts/IUserInteraction.cs | 175 ++++++++++++++++++------ 1 file changed, 132 insertions(+), 43 deletions(-) diff --git a/src/Argon.Contracts/IUserInteraction.cs b/src/Argon.Contracts/IUserInteraction.cs index 98363e98..5c9e6635 100644 --- a/src/Argon.Contracts/IUserInteraction.cs +++ b/src/Argon.Contracts/IUserInteraction.cs @@ -7,65 +7,154 @@ namespace Argon.Contracts; public interface IUserInteraction : IRpcService { - Task GetMe(string username); - Task CreateServer(string username, CreateServerRequest request); - Task> GetServers(string username); + Task GetMe(); + Task CreateServer(CreateServerRequest request); + Task> GetServers(); - Task> GetServerDetails(string username); + Task> GetServerDetails(); // Task CreateChannel(string username); - Task JoinChannel(string username, ChannelJoinRequest request); + Task JoinChannel(ChannelJoinRequest request); } -[DataContract, MemoryPackable(GenerateType.VersionTolerant), MessagePackObject] +[DataContract] +[MemoryPackable(GenerateType.VersionTolerant)] +[MessagePackObject] public sealed partial record UserResponse( - [property: DataMember(Order = 0), MemoryPackOrder(0), Key(0)] Guid Id, - [property: DataMember(Order = 1), MemoryPackOrder(1), Key(1)] string Username, - [property: DataMember(Order = 2), MemoryPackOrder(2), Key(2)] string AvatarUrl, - [property: DataMember(Order = 3), MemoryPackOrder(3), Key(3)] DateTime CreatedAt, - [property: DataMember(Order = 4), MemoryPackOrder(4), Key(4)] DateTime UpdatedAt + [property: DataMember(Order = 0)] + [property: MemoryPackOrder(0)] + [property: Key(0)] + Guid Id, + [property: DataMember(Order = 1)] + [property: MemoryPackOrder(1)] + [property: Key(1)] + string Username, + [property: DataMember(Order = 2)] + [property: MemoryPackOrder(2)] + [property: Key(2)] + string AvatarUrl, + [property: DataMember(Order = 3)] + [property: MemoryPackOrder(3)] + [property: Key(3)] + DateTime CreatedAt, + [property: DataMember(Order = 4)] + [property: MemoryPackOrder(4)] + [property: Key(4)] + DateTime UpdatedAt ); -[DataContract, MemoryPackable(GenerateType.VersionTolerant), MessagePackObject] +[DataContract] +[MemoryPackable(GenerateType.VersionTolerant)] +[MessagePackObject] public sealed partial record CreateServerRequest( - [property: DataMember(Order = 0), MemoryPackOrder(0), Key(0)] string Name, - [property: DataMember(Order = 1), MemoryPackOrder(1), Key(1)] string Description, - [property: DataMember(Order = 2), MemoryPackOrder(2), Key(2)] string AvatarUrl - ); + [property: DataMember(Order = 0)] + [property: MemoryPackOrder(0)] + [property: Key(0)] + string Name, + [property: DataMember(Order = 1)] + [property: MemoryPackOrder(1)] + [property: Key(1)] + string Description, + [property: DataMember(Order = 2)] + [property: MemoryPackOrder(2)] + [property: Key(2)] + string AvatarUrl +); -[DataContract, MemoryPackable(GenerateType.VersionTolerant), MessagePackObject] +[DataContract] +[MemoryPackable(GenerateType.VersionTolerant)] +[MessagePackObject] public sealed partial record ServerResponse( - [property: DataMember(Order = 0), MemoryPackOrder(0), Key(0)] Guid Id, - [property: DataMember(Order = 1), MemoryPackOrder(1), Key(1)] string Name, - [property: DataMember(Order = 2), MemoryPackOrder(2), Key(2)] string Description, - [property: DataMember(Order = 3), MemoryPackOrder(3), Key(3)] string AvatarUrl, - [property: DataMember(Order = 4), MemoryPackOrder(4), Key(4)] List Channels, - [property: DataMember(Order = 5), MemoryPackOrder(5), Key(5)] DateTime CreatedAt, - [property: DataMember(Order = 6), MemoryPackOrder(6), Key(6)] DateTime UpdatedAt + [property: DataMember(Order = 0)] + [property: MemoryPackOrder(0)] + [property: Key(0)] + Guid Id, + [property: DataMember(Order = 1)] + [property: MemoryPackOrder(1)] + [property: Key(1)] + string Name, + [property: DataMember(Order = 2)] + [property: MemoryPackOrder(2)] + [property: Key(2)] + string Description, + [property: DataMember(Order = 3)] + [property: MemoryPackOrder(3)] + [property: Key(3)] + string AvatarUrl, + [property: DataMember(Order = 4)] + [property: MemoryPackOrder(4)] + [property: Key(4)] + List Channels, + [property: DataMember(Order = 5)] + [property: MemoryPackOrder(5)] + [property: Key(5)] + DateTime CreatedAt, + [property: DataMember(Order = 6)] + [property: MemoryPackOrder(6)] + [property: Key(6)] + DateTime UpdatedAt // TODO: all users of the server with their statuses(online/offline/in channel) - ); +); -[DataContract, MemoryPackable(GenerateType.VersionTolerant), MessagePackObject] +[DataContract] +[MemoryPackable(GenerateType.VersionTolerant)] +[MessagePackObject] public sealed partial record ServerDetailsResponse( - [property: DataMember(Order = 0), MemoryPackOrder(0), Key(0)] Guid Id, - [property: DataMember(Order = 1), MemoryPackOrder(1), Key(1)] string Name, - [property: DataMember(Order = 2), MemoryPackOrder(2), Key(2)] string Description, - [property: DataMember(Order = 3), MemoryPackOrder(3), Key(3)] string CreatedBy, - [property: DataMember(Order = 4), MemoryPackOrder(4), Key(4)] string ChannelType, - [property: DataMember(Order = 5), MemoryPackOrder(5), Key(5)] string AccessLevel, - [property: DataMember(Order = 6), MemoryPackOrder(6), Key(6)] DateTime CreatedAt, - [property: DataMember(Order = 7), MemoryPackOrder(7), Key(7)] DateTime UpdatedAt + [property: DataMember(Order = 0)] + [property: MemoryPackOrder(0)] + [property: Key(0)] + Guid Id, + [property: DataMember(Order = 1)] + [property: MemoryPackOrder(1)] + [property: Key(1)] + string Name, + [property: DataMember(Order = 2)] + [property: MemoryPackOrder(2)] + [property: Key(2)] + string Description, + [property: DataMember(Order = 3)] + [property: MemoryPackOrder(3)] + [property: Key(3)] + string CreatedBy, + [property: DataMember(Order = 4)] + [property: MemoryPackOrder(4)] + [property: Key(4)] + string ChannelType, + [property: DataMember(Order = 5)] + [property: MemoryPackOrder(5)] + [property: Key(5)] + string AccessLevel, + [property: DataMember(Order = 6)] + [property: MemoryPackOrder(6)] + [property: Key(6)] + DateTime CreatedAt, + [property: DataMember(Order = 7)] + [property: MemoryPackOrder(7)] + [property: Key(7)] + DateTime UpdatedAt // TODO: all users currently connected to this channel - ); +); -[DataContract, MemoryPackable(GenerateType.VersionTolerant), MessagePackObject] +[DataContract] +[MemoryPackable(GenerateType.VersionTolerant)] +[MessagePackObject] public sealed partial record ChannelJoinRequest( - [property: DataMember(Order = 0), MemoryPackOrder(0), Key(0)] Guid ServerId, - [property: DataMember(Order = 1), MemoryPackOrder(1), Key(1)] Guid ChannelId - ); + [property: DataMember(Order = 0)] + [property: MemoryPackOrder(0)] + [property: Key(0)] + Guid ServerId, + [property: DataMember(Order = 1)] + [property: MemoryPackOrder(1)] + [property: Key(1)] + Guid ChannelId +); -[DataContract, MemoryPackable(GenerateType.VersionTolerant), MessagePackObject] +[DataContract] +[MemoryPackable(GenerateType.VersionTolerant)] +[MessagePackObject] public sealed partial record ChannelJoinResponse( - [property: DataMember(Order = 0), MemoryPackOrder(0), Key(0)] string Token - ); - + [property: DataMember(Order = 0)] + [property: MemoryPackOrder(0)] + [property: Key(0)] + string Token +); \ No newline at end of file From 3dc4f45ad8957165b8021c2d9f1f0c16b5fb5c0f Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 28 Oct 2024 00:00:35 +0400 Subject: [PATCH 5/9] Add UserInteractionService with unimplemented methods --- .../Services/UserInteractionService.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/Argon.Api/Services/UserInteractionService.cs diff --git a/src/Argon.Api/Services/UserInteractionService.cs b/src/Argon.Api/Services/UserInteractionService.cs new file mode 100644 index 00000000..de7b8b20 --- /dev/null +++ b/src/Argon.Api/Services/UserInteractionService.cs @@ -0,0 +1,34 @@ +namespace Argon.Api.Services; + +using Contracts; + +public class UserInteractionService( + string username, // TODO to be injected + IGrainFactory grainFactory +) : IUserInteraction +{ + public Task GetMe() + { + throw new NotImplementedException(); + } + + public Task CreateServer(CreateServerRequest request) + { + throw new NotImplementedException(); + } + + public Task> GetServers() + { + throw new NotImplementedException(); + } + + public Task> GetServerDetails() + { + throw new NotImplementedException(); + } + + public Task JoinChannel(ChannelJoinRequest request) + { + throw new NotImplementedException(); + } +} \ No newline at end of file From d48cef87d113088cefb027ea9a9f1ea99355ca18 Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 28 Oct 2024 00:44:14 +0400 Subject: [PATCH 6/9] Refactor and enhance server and user interaction services --- .../ChannelStorage.cs | 15 +++++++ .../ServerStorage.cs | 14 +++++++ .../UserStorageDto.cs | 14 +++++++ .../Services/UserInteractionService.cs | 39 +++++++++---------- src/Argon.Contracts/Argon.Contracts.csproj | 35 +++++++++-------- src/Argon.Contracts/IUserInteraction.cs | 12 +++++- 6 files changed, 91 insertions(+), 38 deletions(-) diff --git a/src/Argon.Api/Grains.Persistence.States/ChannelStorage.cs b/src/Argon.Api/Grains.Persistence.States/ChannelStorage.cs index 8bf7fbb1..52295b87 100644 --- a/src/Argon.Api/Grains.Persistence.States/ChannelStorage.cs +++ b/src/Argon.Api/Grains.Persistence.States/ChannelStorage.cs @@ -1,5 +1,6 @@ namespace Argon.Api.Grains.Persistence.States; +using Contracts; using MemoryPack; [GenerateSerializer] @@ -16,4 +17,18 @@ public sealed partial record ChannelStorage [Id(5)] public ServerRole AccessLevel { get; set; } = ServerRole.User; [Id(6)] public DateTime CreatedAt { get; } = DateTime.UtcNow; [Id(7)] public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; + + public static implicit operator ServerDetailsResponse(ChannelStorage channelStorage) + { + return new ServerDetailsResponse( + channelStorage.Id, + channelStorage.Name, + channelStorage.Description, + channelStorage.CreatedBy.ToString("N"), + channelStorage.ChannelType.ToString(), + channelStorage.AccessLevel.ToString(), + channelStorage.CreatedAt, + channelStorage.UpdatedAt + ); + } } \ No newline at end of file diff --git a/src/Argon.Api/Grains.Persistence.States/ServerStorage.cs b/src/Argon.Api/Grains.Persistence.States/ServerStorage.cs index d517a3e0..0f16794b 100644 --- a/src/Argon.Api/Grains.Persistence.States/ServerStorage.cs +++ b/src/Argon.Api/Grains.Persistence.States/ServerStorage.cs @@ -1,5 +1,6 @@ namespace Argon.Api.Grains.Persistence.States; +using Contracts; using MemoryPack; [GenerateSerializer] @@ -15,4 +16,17 @@ public sealed partial record ServerStorage [Id(6)] public List Channels { get; set; } = []; [Id(3)] public DateTime CreatedAt { get; } = DateTime.UtcNow; [Id(4)] public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; + + public static implicit operator ServerResponse(ServerStorage serverStorage) + { + return new ServerResponse( + serverStorage.Id, + serverStorage.Name, + serverStorage.Description, + serverStorage.AvatarUrl, + serverStorage.Channels, + serverStorage.CreatedAt, + serverStorage.UpdatedAt + ); + } } \ No newline at end of file diff --git a/src/Argon.Api/Grains.Persistence.States/UserStorageDto.cs b/src/Argon.Api/Grains.Persistence.States/UserStorageDto.cs index 72d03c47..32b44554 100644 --- a/src/Argon.Api/Grains.Persistence.States/UserStorageDto.cs +++ b/src/Argon.Api/Grains.Persistence.States/UserStorageDto.cs @@ -1,11 +1,14 @@ namespace Argon.Api.Grains.Persistence.States; +using Contracts; +using Mapster; using MemoryPack; [GenerateSerializer] [Serializable] [MemoryPackable] [Alias(nameof(UserStorageDto))] +[GenerateMapper] public sealed partial record UserStorageDto { [Id(0)] public Guid Id { get; set; } @@ -13,4 +16,15 @@ public sealed partial record UserStorageDto [Id(4)] public string AvatarUrl { get; set; } = string.Empty; [Id(2)] public DateTime CreatedAt { get; set; } [Id(3)] public DateTime UpdatedAt { get; set; } + + public static implicit operator UserResponse(UserStorageDto userStorageDto) + { + return new UserResponse( + userStorageDto.Id, + userStorageDto.Username, + userStorageDto.AvatarUrl, + userStorageDto.CreatedAt, + userStorageDto.UpdatedAt + ); + } } \ No newline at end of file diff --git a/src/Argon.Api/Services/UserInteractionService.cs b/src/Argon.Api/Services/UserInteractionService.cs index de7b8b20..cbb229f8 100644 --- a/src/Argon.Api/Services/UserInteractionService.cs +++ b/src/Argon.Api/Services/UserInteractionService.cs @@ -1,34 +1,33 @@ namespace Argon.Api.Services; using Contracts; +using Grains.Interfaces; public class UserInteractionService( string username, // TODO to be injected IGrainFactory grainFactory ) : IUserInteraction { - public Task GetMe() - { - throw new NotImplementedException(); - } + public async Task GetMe() => await grainFactory.GetGrain(username).Get(); - public Task CreateServer(CreateServerRequest request) - { - throw new NotImplementedException(); - } + public async Task CreateServer(CreateServerRequest request) => + await grainFactory + .GetGrain(username) + .CreateServer(request.Name, request.Description); - public Task> GetServers() - { - throw new NotImplementedException(); - } + public async Task> GetServers() => + (await grainFactory + .GetGrain(username) + .GetServers()) + .Select(x => (ServerResponse)x) + .ToList(); - public Task> GetServerDetails() - { - throw new NotImplementedException(); - } + public async Task> GetServerDetails(ServerDetailsRequest request) => + (await grainFactory.GetGrain(username).GetServerChannels(request.ServerId)) + .Select(x => (ServerDetailsResponse)x) + .ToList(); - public Task JoinChannel(ChannelJoinRequest request) - { - throw new NotImplementedException(); - } + public async Task JoinChannel(ChannelJoinRequest request) => + new((await grainFactory.GetGrain(username) + .JoinChannel(request.ServerId, request.ChannelId)).value); } \ No newline at end of file diff --git a/src/Argon.Contracts/Argon.Contracts.csproj b/src/Argon.Contracts/Argon.Contracts.csproj index cd6dcee5..6f90131f 100644 --- a/src/Argon.Contracts/Argon.Contracts.csproj +++ b/src/Argon.Contracts/Argon.Contracts.csproj @@ -1,22 +1,23 @@  - - net8.0 - enable - enable - + + net8.0 + enable + enable + - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/src/Argon.Contracts/IUserInteraction.cs b/src/Argon.Contracts/IUserInteraction.cs index 5c9e6635..39fad3dc 100644 --- a/src/Argon.Contracts/IUserInteraction.cs +++ b/src/Argon.Contracts/IUserInteraction.cs @@ -11,12 +11,22 @@ public interface IUserInteraction : IRpcService Task CreateServer(CreateServerRequest request); Task> GetServers(); - Task> GetServerDetails(); + Task> GetServerDetails(ServerDetailsRequest request); // Task CreateChannel(string username); Task JoinChannel(ChannelJoinRequest request); } +[DataContract] +[MemoryPackable(GenerateType.VersionTolerant)] +[MessagePackObject] +public sealed partial record ServerDetailsRequest( + [property: DataMember(Order = 0)] + [property: MemoryPackOrder(0)] + [property: Key(0)] + Guid ServerId +); + [DataContract] [MemoryPackable(GenerateType.VersionTolerant)] [MessagePackObject] From 8078d0bc17de4f384891a13b990e7ee2162307b4 Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 28 Oct 2024 00:44:57 +0400 Subject: [PATCH 7/9] Add IUserInteraction RPC server to Fusion --- src/Argon.Api/Program.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Argon.Api/Program.cs b/src/Argon.Api/Program.cs index d3d4bc06..343dfc02 100644 --- a/src/Argon.Api/Program.cs +++ b/src/Argon.Api/Program.cs @@ -18,6 +18,7 @@ builder.Services.AddControllers(opts => { opts.Filters.Add(); }); builder.Services.AddFusion(RpcServiceMode.Server, true) .Rpc.AddServer() + .AddServer() .AddWebSocketServer(true); builder.AddSwaggerWithAuthHeader(); builder.AddJwt(); From bce9f4bf5c6715d57c03445f3868f703ba401b14 Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 28 Oct 2024 02:16:49 +0400 Subject: [PATCH 8/9] Rename 'Authenticate' to 'Authorize' in IUserManager interface --- src/Argon.Api/Grains.Interfaces/IUserManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Argon.Api/Grains.Interfaces/IUserManager.cs b/src/Argon.Api/Grains.Interfaces/IUserManager.cs index c2b54948..2829a54a 100644 --- a/src/Argon.Api/Grains.Interfaces/IUserManager.cs +++ b/src/Argon.Api/Grains.Interfaces/IUserManager.cs @@ -11,7 +11,7 @@ public interface IUserManager : IGrainWithStringKey [Alias("Get")] Task Get(); - [Alias("Authenticate")] + [Alias("Authorize")] Task Authorize(string password); [Alias("CreateServer")] From f6496884331ef7f4642079a72d3025d72df64180 Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 28 Oct 2024 02:20:36 +0400 Subject: [PATCH 9/9] Refactor UserInteractionService to reuse IUserManager instance --- .../Services/UserInteractionService.cs | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/Argon.Api/Services/UserInteractionService.cs b/src/Argon.Api/Services/UserInteractionService.cs index cbb229f8..85798eb6 100644 --- a/src/Argon.Api/Services/UserInteractionService.cs +++ b/src/Argon.Api/Services/UserInteractionService.cs @@ -8,26 +8,34 @@ public class UserInteractionService( IGrainFactory grainFactory ) : IUserInteraction { - public async Task GetMe() => await grainFactory.GetGrain(username).Get(); + private readonly IUserManager userManager = grainFactory.GetGrain(username); - public async Task CreateServer(CreateServerRequest request) => - await grainFactory - .GetGrain(username) - .CreateServer(request.Name, request.Description); + public async Task GetMe() + { + return await userManager.Get(); + } - public async Task> GetServers() => - (await grainFactory - .GetGrain(username) - .GetServers()) - .Select(x => (ServerResponse)x) - .ToList(); + public async Task CreateServer(CreateServerRequest request) + { + return await userManager.CreateServer(request.Name, request.Description); + } - public async Task> GetServerDetails(ServerDetailsRequest request) => - (await grainFactory.GetGrain(username).GetServerChannels(request.ServerId)) - .Select(x => (ServerDetailsResponse)x) - .ToList(); + public async Task> GetServers() + { + return (await userManager.GetServers()) + .Select(x => (ServerResponse)x) + .ToList(); + } - public async Task JoinChannel(ChannelJoinRequest request) => - new((await grainFactory.GetGrain(username) - .JoinChannel(request.ServerId, request.ChannelId)).value); + public async Task> GetServerDetails(ServerDetailsRequest request) + { + return (await userManager.GetServerChannels(request.ServerId)) + .Select(x => (ServerDetailsResponse)x) + .ToList(); + } + + public async Task JoinChannel(ChannelJoinRequest request) + { + return new ChannelJoinResponse((await userManager.JoinChannel(request.ServerId, request.ChannelId)).value); + } } \ No newline at end of file