Skip to content

Commit 43f10cc

Browse files
committed
refactoring
1 parent 477d6dc commit 43f10cc

94 files changed

Lines changed: 4203 additions & 2553 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/dotnet.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
run: dotnet restore
2929

3030
- name: Build
31-
run: dotnet build --no-restore
31+
run: dotnet build --no-restore --warnaserror
3232

3333
- name: Test and Collect Code Coverage
3434
run: dotnet test -p:CollectCoverage=true -p:CoverletOutput=coverage/
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using AIBase.Abstractions.Chat.Grains;
2+
using AIBase.Abstractions.Chat.Models;
3+
using Microsoft.Extensions.Logging;
4+
5+
namespace AIBase.Core.Grains.Implementations;
6+
7+
public partial class UserGrain
8+
{
9+
public async Task<List<ChatMember>> GetChatMembershipsAsync()
10+
{
11+
if (!state.RecordExists)
12+
return new List<ChatMember>();
13+
14+
var chatMembers = new List<ChatMember>();
15+
var chatIds = state.State.ChatIds;
16+
17+
foreach (var chatId in chatIds)
18+
{
19+
var chatGrain = GrainFactory.GetGrain<IChatGrain>(chatId);
20+
var chatState = await chatGrain.GetChatStateAsync();
21+
if (chatState.Status != ChatStatus.Archived)
22+
{
23+
chatMembers.Add(new ChatMember(
24+
Id: chatId,
25+
Type: ChatMemberType.User, // Using User type for chats in user's list
26+
Name: chatId, // TODO: Store chat title in user grain
27+
JoinedAt: DateTime.UtcNow
28+
));
29+
}
30+
}
31+
32+
return chatMembers;
33+
}
34+
35+
public async Task AddChatMembershipAsync(ChatMember chatMember)
36+
{
37+
if (!state.RecordExists) return;
38+
39+
if (!state.State.ChatIds.Contains(chatMember.Id))
40+
{
41+
state.State.ChatIds.Insert(0, chatMember.Id); // Add to beginning for recent chats
42+
await state.WriteStateAsync();
43+
logger.LogInformation("Added chat {ChatId} to user {UserId}", chatMember.Id, state.State.Id);
44+
}
45+
}
46+
47+
public async Task RemoveChatMembershipAsync(string chatId)
48+
{
49+
if (!state.RecordExists) return;
50+
51+
if (state.State.ChatIds.Remove(chatId))
52+
{
53+
await state.WriteStateAsync();
54+
logger.LogInformation("Removed chat {ChatId} from user {UserId}", chatId, state.State.Id);
55+
}
56+
}
57+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using AIBase.Abstractions.UserManagement.Models;
2+
using Microsoft.Extensions.Logging;
3+
4+
namespace AIBase.Core.Grains.Implementations;
5+
6+
public partial class UserGrain
7+
{
8+
public async Task UpdateSettingsAsync(UserSettings settings)
9+
{
10+
if (!state.RecordExists) return;
11+
12+
state.State = state.State with { Settings = settings };
13+
await state.WriteStateAsync();
14+
logger.LogInformation("Updated settings for user {UserId}", state.State.Id);
15+
}
16+
}

Directory.Build.props

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<LangVersion>13</LangVersion>
55
<EnableNETAnalyzers>true</EnableNETAnalyzers>
66
<Nullable>enable</Nullable>
7+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
78
</PropertyGroup>
89

910
<!--NuGet-->
@@ -24,8 +25,8 @@
2425
<RepositoryUrl>https://github.com/managedcode/Communication</RepositoryUrl>
2526
<PackageProjectUrl>https://github.com/managedcode/Communication</PackageProjectUrl>
2627
<Product>Managed Code - Communication</Product>
27-
<Version>9.0.1</Version>
28-
<PackageVersion>9.0.1</PackageVersion>
28+
<Version>9.5.0</Version>
29+
<PackageVersion>9.5.0</PackageVersion>
2930

3031
</PropertyGroup>
3132
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">

ManagedCode.Communication.Benchmark/CreateInstanceFailBenchmark.cs

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,34 +55,26 @@ public Result ActivatorCreateInstanceGenericInt()
5555

5656

5757
[Benchmark]
58-
public object? ActivatorCreateInstanceTypeError()
58+
public Result CreateInstanceTypeError()
5959
{
60-
var result = (Result)Activator.CreateInstance(typeof(Result));
61-
result.Errors = new[] { Error.Create("oops") };
62-
return result;
60+
return Result.Fail("about:blank", "Error", System.Net.HttpStatusCode.BadRequest);
6361
}
6462

6563
[Benchmark]
66-
public object? ActivatorCreateInstanceTypeIntError()
64+
public Result<int> CreateInstanceTypeIntError()
6765
{
68-
var result = (Result<int>)Activator.CreateInstance(typeof(Result<int>));
69-
result.Errors = new[] { Error.Create("oops") };
70-
return result;
66+
return Result<int>.Fail("about:blank", "Error", System.Net.HttpStatusCode.BadRequest);
7167
}
7268

7369
[Benchmark]
74-
public object? ActivatorCreateInstanceTypeErrorInterface()
70+
public Result CreateInstanceTypeErrorInterface()
7571
{
76-
var result = Activator.CreateInstance(typeof(Result));
77-
(result as IResultError).AddError(Error.Create("oops"));
78-
return result;
72+
return Result.Fail("about:blank", "Error", System.Net.HttpStatusCode.BadRequest);
7973
}
8074

8175
[Benchmark]
82-
public object? ActivatorCreateInstanceTypeIntErrorInterface()
76+
public Result<int> CreateInstanceTypeIntErrorInterface()
8377
{
84-
var result = Activator.CreateInstance(typeof(Result<int>));
85-
(result as IResultError).AddError(Error.Create("oops"));
86-
return result;
78+
return Result<int>.Fail("about:blank", "Error", System.Net.HttpStatusCode.BadRequest);
8779
}
8880
}

ManagedCode.Communication.Benchmark/ManagedCode.Communication.Benchmark.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
</PropertyGroup>
1010

1111
<ItemGroup>
12-
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
12+
<PackageReference Include="BenchmarkDotNet" Version="0.15.2" />
1313
</ItemGroup>
1414

1515
<ItemGroup>
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Globalization;
4+
using System.Net;
5+
using System.Reflection;
6+
using BenchmarkDotNet.Attributes;
7+
8+
namespace ManagedCode.Communication.Benchmark;
9+
10+
[MemoryDiagnoser]
11+
[SimpleJob(warmupCount: 3, iterationCount: 10)]
12+
public class ResultCreationBenchmark
13+
{
14+
private static readonly Exception TestException = new InvalidOperationException("Benchmark test");
15+
private static readonly Type ResultIntType = typeof(Result<int>);
16+
private static readonly ConcurrentDictionary<Type, MethodInfo> MethodCache = new();
17+
18+
private MethodInfo _cachedMethod = null!;
19+
private readonly object[] _exceptionArray = new object[1];
20+
private readonly Exception _exception = TestException;
21+
22+
[GlobalSetup]
23+
public void Setup()
24+
{
25+
_cachedMethod = ResultIntType.GetMethod(nameof(Result.Fail), [typeof(Exception), typeof(HttpStatusCode)])!;
26+
MethodCache[ResultIntType] = _cachedMethod;
27+
_exceptionArray[0] = TestException;
28+
}
29+
30+
[Benchmark(Baseline = true)]
31+
public Result<int> DirectCall()
32+
{
33+
return Result<int>.Fail(TestException);
34+
}
35+
36+
[Benchmark]
37+
public object Reflection_FindMethodEveryTime()
38+
{
39+
var method = ResultIntType.GetMethod(nameof(Result.Fail), [typeof(Exception), typeof(HttpStatusCode)]);
40+
return method!.Invoke(null, [TestException, HttpStatusCode.InternalServerError])!;
41+
}
42+
43+
[Benchmark]
44+
public object Reflection_CachedMethod()
45+
{
46+
return _cachedMethod.Invoke(null, [TestException, HttpStatusCode.InternalServerError])!;
47+
}
48+
49+
[Benchmark]
50+
public object Reflection_CachedMethod_ReuseArray()
51+
{
52+
// Can't reuse array because we need 2 parameters
53+
return _cachedMethod.Invoke(null, [TestException, HttpStatusCode.InternalServerError])!;
54+
}
55+
56+
[Benchmark]
57+
public object Reflection_ConcurrentDictionary()
58+
{
59+
var method = MethodCache.GetOrAdd(ResultIntType, type =>
60+
type.GetMethod(nameof(Result.Fail), [typeof(Exception), typeof(HttpStatusCode)])!);
61+
return method.Invoke(null, [TestException, HttpStatusCode.InternalServerError])!;
62+
}
63+
64+
[Benchmark]
65+
public object Activator_TryCreateInstance()
66+
{
67+
var result = Activator.CreateInstance(ResultIntType);
68+
return result!;
69+
}
70+
71+
[Benchmark]
72+
public object Activator_WithPropertySet()
73+
{
74+
var resultType = Activator.CreateInstance(ResultIntType,
75+
BindingFlags.NonPublic | BindingFlags.Instance,
76+
null, [TestException],
77+
CultureInfo.CurrentCulture);
78+
79+
return resultType!;
80+
}
81+
}

ManagedCode.Communication.Extensions/Constants/ProblemConstants.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,20 @@ public static class ExtensionKeys
5555
/// Key for stack trace in problem extensions
5656
/// </summary>
5757
public const string StackTrace = "stackTrace";
58+
59+
/// <summary>
60+
/// Key for error type (enum type name) in problem extensions
61+
/// </summary>
62+
public const string ErrorType = "errorType";
63+
64+
/// <summary>
65+
/// Key for error code name (enum value name) in problem extensions
66+
/// </summary>
67+
public const string ErrorCodeName = "errorCodeName";
68+
69+
/// <summary>
70+
/// Key for error code value (enum numeric value) in problem extensions
71+
/// </summary>
72+
public const string ErrorCodeValue = "errorCodeValue";
5873
}
5974
}

ManagedCode.Communication.Extensions/Extensions/ControllerExtensions.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ namespace ManagedCode.Communication.Extensions.Extensions;
55

66
public static class ControllerExtensions
77
{
8-
public static IActionResult ToActionResult<T>(this Result<T> result)
8+
public static IActionResult ToActionResult<T>(this ManagedCode.Communication.Result<T> result)
99
{
1010
return result.IsSuccess
1111
? new OkObjectResult(result.Value)
12-
: new BadRequestObjectResult(result.GetError()?.Message);
12+
: new BadRequestObjectResult(result.Problem?.Detail ?? "Operation failed");
1313
}
1414

15-
public static Microsoft.AspNetCore.Http.IResult ToHttpResult<T>(this Result<T> result)
15+
public static Microsoft.AspNetCore.Http.IResult ToHttpResult<T>(this ManagedCode.Communication.Result<T> result)
1616
{
17-
return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.GetError()?.Message);
17+
return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Problem?.Detail ?? "Operation failed");
1818
}
1919
}

ManagedCode.Communication.Extensions/Extensions/HubOptionsExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Microsoft.AspNetCore.SignalR;
33
using Microsoft.Extensions.DependencyInjection;
44
using ManagedCode.Communication.Extensions;
5+
using ManagedCode.Communication.Extensions.Filters;
56

67
namespace ManagedCode.Communication.Extensions.Extensions;
78

0 commit comments

Comments
 (0)