feat(calls): add consent-based signaling to existing ChatHub
Wire shared PostIt call signaling, account-derived relay policy and temporary TURN credentials. Keep calls disabled pending native Android/Linux media integration. Document experimental Android crash and laboratory removal. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
56ca115f50
commit
5e48831d6d
20 changed files with 1368 additions and 16 deletions
|
|
@ -4,10 +4,15 @@ using System.Net.Http.Json;
|
|||
using System.Text.Json;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Yavsc.Abstract.Identity;
|
||||
using Yavsc.Abstract.Chat.Calls;
|
||||
using Yavsc.Api.Test.Fixtures;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Tests.Shared;
|
||||
using Yavsc.Services;
|
||||
using Yavsc.Settings;
|
||||
|
||||
namespace Yavsc.Api.Test;
|
||||
|
||||
|
|
@ -146,4 +151,32 @@ public sealed class AccountCallPreferenceTests(ApiWebServerFixture fixture) : IC
|
|||
Assert.False(profile.HideIpAddressInCalls);
|
||||
Assert.NotEqual("Must not be saved", profile.FullName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Activating_privacy_ends_an_existing_call_before_returning_success()
|
||||
{
|
||||
var ct = TestContext.Current.CancellationToken;
|
||||
var id = await CreateUserAsync();
|
||||
var other = await CreateUserAsync();
|
||||
var options = fixture.Services.GetRequiredService<IOptions<AudioVideoCallOptions>>().Value;
|
||||
var calls = fixture.Services.GetRequiredService<CallSignalingService>();
|
||||
var delivery = fixture.Services.GetRequiredService<RecordingMessageDelivery>();
|
||||
options.Enabled = true;
|
||||
try
|
||||
{
|
||||
var call = await calls.InviteAsync("General", id, other, "preference-caller", ["preference-callee"], false);
|
||||
await calls.AcceptAsync(call.Id, other, "preference-callee", false);
|
||||
using var client = Client(id);
|
||||
using var response = await client.PutAsJsonAsync(Endpoint, new { hideIpAddressInCalls = true }, ct);
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Contains(delivery.Pushes, p => p.Method == CallHubMethods.Ended &&
|
||||
p.Arguments[0] is CallEnded ended && ended.CallId == call.Id && ended.Reason == "profile-changed");
|
||||
await Assert.ThrowsAsync<HubException>(() => calls.GetSessionAsync(call.Id, id, "preference-caller"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
await calls.EndForUserAsync(id, "test-cleanup");
|
||||
options.Enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,9 @@ public sealed class ApiWebServerFixture : WebHostFixture
|
|||
builder.Services.AddTransient<ICalendarManager, CalendarManager>();
|
||||
builder.Services.AddSingleton<IHubContext<ChatHub>>(sp => sp.GetRequiredService<RecordingMessageDelivery>());
|
||||
builder.Services.AddSingleton<IConnexionManager, HubConnectionManager>();
|
||||
builder.Services.Configure<Yavsc.Settings.AudioVideoCallOptions>(_ => { });
|
||||
builder.Services.AddSingleton(TimeProvider.System);
|
||||
builder.Services.AddSingleton<CallSignalingService>();
|
||||
builder.Services.AddTransient<IYavscMessageSender, YavscMessageSender>();
|
||||
builder.Services.AddAuthorization(options =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ public sealed class RecordingMessageDelivery : ITrueEmailSender, IHubContext<Cha
|
|||
IGroupManager IHubContext<ChatHub>.Groups => throw new NotSupportedException();
|
||||
public IClientProxy All => throw new NotSupportedException();
|
||||
public IClientProxy AllExcept(IReadOnlyList<string> excludedConnectionIds) => throw new NotSupportedException();
|
||||
public IClientProxy Client(string connectionId) => new RecordingClient(this, connectionId);
|
||||
public IClientProxy Clients(IReadOnlyList<string> connectionIds) => throw new NotSupportedException();
|
||||
public IClientProxy Client(string connectionId) => new RecordingClient(this, [connectionId]);
|
||||
public IClientProxy Clients(IReadOnlyList<string> connectionIds) => new RecordingClient(this, connectionIds);
|
||||
public IClientProxy Group(string groupName) => throw new NotSupportedException();
|
||||
public IClientProxy GroupExcept(string groupName, IReadOnlyList<string> excludedConnectionIds) => throw new NotSupportedException();
|
||||
public IClientProxy Groups(IReadOnlyList<string> groupNames) => throw new NotSupportedException();
|
||||
|
|
@ -36,11 +36,12 @@ public sealed class RecordingMessageDelivery : ITrueEmailSender, IHubContext<Cha
|
|||
Pushes.Clear();
|
||||
}
|
||||
|
||||
private sealed class RecordingClient(RecordingMessageDelivery delivery, string connectionId) : IClientProxy
|
||||
private sealed class RecordingClient(RecordingMessageDelivery delivery, IReadOnlyList<string> connectionIds) : IClientProxy
|
||||
{
|
||||
public Task SendCoreAsync(string method, object?[] args, CancellationToken cancellationToken = default)
|
||||
{
|
||||
delivery.Pushes.Enqueue(new Push(connectionId, method, args));
|
||||
foreach (var connectionId in connectionIds)
|
||||
delivery.Pushes.Enqueue(new Push(connectionId, method, args));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue