-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPairingHandler.cs
More file actions
108 lines (99 loc) · 4.74 KB
/
Copy pathPairingHandler.cs
File metadata and controls
108 lines (99 loc) · 4.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
using Microsoft.Extensions.Logging;
using RustPlusBot.Abstractions.Credentials;
using RustPlusBot.Abstractions.Events;
using RustPlusBot.Features.Pairing.Listening;
using RustPlusBot.Persistence.Servers;
namespace RustPlusBot.Features.Pairing.Pairing;
/// <summary>Default <see cref="IPairingHandler"/>: known servers get a silent credential upsert; new servers
/// are routed to the #setup confirmation prompt; entity pairings fan out to their feature events.</summary>
/// <param name="servers">Server lookup/backfill.</param>
/// <param name="credentials">The credential pool store.</param>
/// <param name="eventBus">Publishes the entity paired events.</param>
/// <param name="serverPairings">Prompts for confirmation before a new server is registered.</param>
/// <param name="logger">The logger.</param>
internal sealed partial class PairingHandler(
IServerService servers,
ICredentialStore credentials,
IEventBus eventBus,
IServerPairingCoordinator serverPairings,
ILogger<PairingHandler> logger) : IPairingHandler
{
/// <inheritdoc />
public async Task HandleAsync(
ulong guildId,
ulong ownerUserId,
PairingNotification notification,
CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(notification);
if (notification.Kind == PairingKind.Entity)
{
await HandleEntityAsync(guildId, notification, cancellationToken).ConfigureAwait(false);
return;
}
var existing = await servers.GetByEndpointAsync(guildId, notification.Ip, notification.Port, cancellationToken)
.ConfigureAwait(false);
if (existing is null)
{
// New server: nothing is persisted until the user accepts the #setup prompt.
await serverPairings.HandleDetectedAsync(guildId, ownerUserId, notification, cancellationToken)
.ConfigureAwait(false);
return;
}
// Only backfill a real Facepunch GUID. Persisting Guid.Empty would make every server that paired
// without one share the same id, breaking GUID-based entity-pairing attribution.
if (notification.FacepunchServerId != Guid.Empty)
{
await servers.SetFacepunchServerIdAsync(existing.Id, notification.FacepunchServerId, cancellationToken)
.ConfigureAwait(false);
}
await credentials.UpsertFromPairingAsync(
new StoreCredentialRequest(guildId, existing.Id, ownerUserId, notification.PlayerId,
notification.PlayerToken),
markActive: false,
cancellationToken).ConfigureAwait(false);
}
private async Task HandleEntityAsync(
ulong guildId,
PairingNotification notification,
CancellationToken cancellationToken)
{
var server = await servers
.GetByFacepunchServerIdAsync(guildId, notification.FacepunchServerId, cancellationToken)
.ConfigureAwait(false);
if (server is null)
{
// Never create a server from an entity pairing; an unknown Facepunch server is logged and dropped.
LogUnknownEntityServer(logger, notification.FacepunchServerId);
return;
}
switch (notification.EntityKind)
{
case RustPlusBot.Domain.Entities.PairedEntityKind.SmartSwitch:
await eventBus
.PublishAsync(new SwitchPairedEvent(guildId, server.Id, notification.EntityId), cancellationToken)
.ConfigureAwait(false);
break;
case RustPlusBot.Domain.Entities.PairedEntityKind.SmartAlarm:
await eventBus
.PublishAsync(new AlarmPairedEvent(guildId, server.Id, notification.EntityId), cancellationToken)
.ConfigureAwait(false);
break;
case RustPlusBot.Domain.Entities.PairedEntityKind.StorageMonitor:
await eventBus
.PublishAsync(new StorageMonitorPairedEvent(guildId, server.Id, notification.EntityId),
cancellationToken)
.ConfigureAwait(false);
break;
default:
LogUnroutedEntityKind(logger, notification.EntityKind);
break;
}
}
[LoggerMessage(Level = LogLevel.Debug,
Message = "Dropping entity pairing for unknown Facepunch server {FacepunchServerId} (no matching server).")]
private static partial void LogUnknownEntityServer(ILogger logger, Guid facepunchServerId);
[LoggerMessage(Level = LogLevel.Debug, Message = "Dropping entity pairing of unrouted kind {Kind}.")]
private static partial void
LogUnroutedEntityKind(ILogger logger, RustPlusBot.Domain.Entities.PairedEntityKind kind);
}