using Kbx.Shared.Experiments.Generated; using Kbx.Shared.Runtime; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.SignalR; namespace Kbx.Shared.Experiments; public sealed record KbxExperimentChangedEvent(string ExperimentId,string ScreenId,DateTimeOffset ChangedAt); [Authorize] public sealed class KbxExperimentHub : Hub { public override async Task OnConnectedAsync() { var tenantId=RuntimeIdentity.TenantId(Context.User!); if(tenantId!=Guid.Empty)await Groups.AddToGroupAsync(Context.ConnectionId,$"experiment-tenant:{tenantId:N}"); await base.OnConnectedAsync(); } } public sealed class KbxExperimentRolloutPublisher(IHubContext hub) { public Task PublishAsync(Guid tenantId,string experimentId,CancellationToken ct) { var screenId=KbxExperimentCatalog.Experiments.TryGetValue(experimentId,out var definition)?definition.ScreenId:string.Empty; return hub.Clients.Group($"experiment-tenant:{tenantId:N}").SendAsync("ExperimentChanged",new KbxExperimentChangedEvent(experimentId,screenId,DateTimeOffset.UtcNow),ct); } } public static class KbxExperimentRegistration { public static IServiceCollection AddKbxExperiments(this IServiceCollection services) { services.AddSignalR();services.AddSingleton();services.AddSingleton();services.AddSingleton();services.AddSingleton();services.AddTransient();return services; } public static IEndpointRouteBuilder MapKbxExperiments(this IEndpointRouteBuilder endpoints){endpoints.MapHub("/hubs/kbx-experiments");return endpoints;} }