Iceshrimp.NET/Iceshrimp.Backend/Core/Services/RelayService.cs
2024-11-20 00:48:29 +01:00

76 lines
No EOL
2.6 KiB
C#

using Iceshrimp.Backend.Core.Database;
using Iceshrimp.Backend.Core.Database.Tables;
using Iceshrimp.Backend.Core.Extensions;
using Iceshrimp.Backend.Core.Helpers;
using Iceshrimp.Backend.Core.Middleware;
using Microsoft.EntityFrameworkCore;
namespace Iceshrimp.Backend.Core.Services;
public class RelayService(
DatabaseContext db,
SystemUserService systemUserSvc,
ActivityPub.ActivityRenderer activityRenderer,
ActivityPub.ActivityDeliverService deliverSvc,
ActivityPub.UserRenderer userRenderer
) : IScopedService
{
public async Task SubscribeToRelayAsync(string uri)
{
uri = new Uri(uri).AbsoluteUri;
if (await db.Relays.AnyAsync(p => p.Inbox == uri)) return;
var relay = new Relay
{
Id = IdHelpers.GenerateSnowflakeId(),
Inbox = uri,
Status = Relay.RelayStatus.Requesting
};
db.Add(relay);
await db.SaveChangesAsync();
var actor = await systemUserSvc.GetRelayActorAsync();
var activity = activityRenderer.RenderFollow(actor, relay);
await deliverSvc.DeliverToAsync(activity, actor, uri);
}
public async Task UnsubscribeFromRelayAsync(Relay relay)
{
var actor = await systemUserSvc.GetRelayActorAsync();
var follow = activityRenderer.RenderFollow(actor, relay);
var activity = activityRenderer.RenderUndo(userRenderer.RenderLite(actor), follow);
await deliverSvc.DeliverToAsync(activity, actor, relay.Inbox);
db.Remove(relay);
await db.SaveChangesAsync();
}
public async Task HandleAcceptAsync(User actor, string id)
{
// @formatter:off
if (await db.Relays.FirstOrDefaultAsync(p => p.Id == id) is not { } relay)
throw GracefulException.UnprocessableEntity($"Relay with id {id} was not found");
if (relay.Inbox != new Uri(actor.Inbox ?? throw new Exception("Relay actor must have an inbox")).AbsoluteUri)
throw GracefulException.UnprocessableEntity($"Relay inbox ({relay.Inbox}) does not match relay actor inbox ({actor.Inbox})");
// @formatter:on
relay.Status = Relay.RelayStatus.Accepted;
actor.IsRelayActor = true;
await db.SaveChangesAsync();
}
public async Task HandleRejectAsync(User actor, string id)
{
// @formatter:off
if (db.Relays.FirstOrDefault(p => p.Id == id) is not { } relay)
throw GracefulException.UnprocessableEntity($"Relay with id {id} was not found");
if (relay.Inbox != new Uri(actor.Inbox ?? throw new Exception("Relay actor must have an inbox")).AbsoluteUri)
throw GracefulException.UnprocessableEntity($"Relay inbox ({relay.Inbox}) does not match relay actor inbox ({actor.Inbox})");
// @formatter:on
relay.Status = Relay.RelayStatus.Rejected;
actor.IsRelayActor = true;
await db.SaveChangesAsync();
}
}