Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="10.0.11" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.11" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.11" />
<PackageVersion Include="Persistord.Core" Version="1.0.0-beta2" />
<PackageVersion Include="Persistord.Core" Version="1.0.0-beta.3" />
<PackageVersion Include="Persistord.Managed" Version="1.0.0-beta.3" />
<PackageVersion Include="RustMapsApi" Version="1.0.0-beta.3" />
<PackageVersion Include="RustMapsApi.Assets" Version="1.0.0-beta.3" />
<PackageVersion Include="RustPlusApi" Version="2.0.0-beta.8" />
Expand All @@ -38,6 +39,7 @@
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="4.0.0" />
<PackageVersion Include="NSubstitute" Version="6.2.0" />
<PackageVersion Include="Persistord.Testing" Version="1.0.0-beta.3" />
<PackageVersion Include="Xunit.SkippableFact" Version="1.5.85" />
</ItemGroup>
<ItemGroup>
Expand Down
15 changes: 8 additions & 7 deletions src/RustPlusBot.Domain/Alarms/SmartAlarm.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
using Persistord.Core.Abstractions;
using RustPlusBot.Abstractions.Connections;

namespace RustPlusBot.Domain.Alarms;

/// <summary>A paired Smart Alarm the bot manages, surviving restarts. Guild- and server-scoped. Driven by the live socket (primed on connect, reacts to SmartDeviceTriggered) — the entity id is the switch-vs-alarm discriminant.</summary>
public sealed class SmartAlarm
public sealed class SmartAlarm : IGuildScoped, ICreatedAt
{
/// <summary>Surrogate primary key.</summary>
public Guid Id { get; set; } = Guid.NewGuid();

/// <summary>The owning Discord guild snowflake.</summary>
public ulong GuildId { get; set; }

/// <summary>The server this alarm belongs to (FK to RustServer, cascade delete).</summary>
public Guid ServerId { get; set; }

Expand All @@ -26,9 +24,6 @@ public sealed class SmartAlarm
/// <summary>The Discord user who accepted (validated) the pairing.</summary>
public ulong PairedByUserId { get; set; }

/// <summary>When the alarm was accepted (UTC).</summary>
public DateTimeOffset CreatedUtc { get; set; }

/// <summary>When true, a trigger going active pings @everyone in #alarms.</summary>
public bool PingEveryone { get; set; }

Expand All @@ -43,4 +38,10 @@ public sealed class SmartAlarm

/// <summary>Per-device reachability; defaults to Reachable. Orthogonal to whole-server connection status.</summary>
public DeviceReachability Reachability { get; set; } = DeviceReachability.Reachable;

/// <summary>When the alarm was accepted (UTC). Stamped by Persistord's TimestampInterceptor.</summary>
public DateTimeOffset CreatedAt { get; set; }

/// <summary>The owning Discord guild snowflake.</summary>
public ulong GuildId { get; set; }
}
14 changes: 8 additions & 6 deletions src/RustPlusBot.Domain/Clans/ClanPlayerName.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using Persistord.Core.Abstractions;

namespace RustPlusBot.Domain.Clans;

/// <summary>
/// A cached Steam64 id to display-name mapping. The clan API reports members by id only, so names
/// are harvested from clan chat and team snapshots, which do carry them.
/// </summary>
public sealed class ClanPlayerName
public sealed class ClanPlayerName : IGuildScoped, IUpdatedAt
{
/// <summary>The owning guild snowflake.</summary>
public ulong GuildId { get; set; }

/// <summary>The server id (FK to RustServer).</summary>
public Guid ServerId { get; set; }

Expand All @@ -18,6 +17,9 @@ public sealed class ClanPlayerName
/// <summary>The most recently observed display name.</summary>
public string Name { get; set; } = string.Empty;

/// <summary>When the name was last observed (UTC).</summary>
public DateTimeOffset UpdatedUtc { get; set; }
/// <summary>The owning guild snowflake.</summary>
public ulong GuildId { get; set; }

/// <summary>When the name was last observed (UTC). Stamped by Persistord's TimestampInterceptor.</summary>
public DateTimeOffset UpdatedAt { get; set; }
}
10 changes: 6 additions & 4 deletions src/RustPlusBot.Domain/Clans/ClanState.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using Persistord.Core.Abstractions;

namespace RustPlusBot.Domain.Clans;

/// <summary>
/// The latest known clan snapshot for one (guild, server). Row presence is the single source of
/// truth for whether the paired player is in a clan.
/// </summary>
public sealed class ClanState
public sealed class ClanState : IGuildScoped
{
/// <summary>The owning guild snowflake.</summary>
public ulong GuildId { get; set; }

/// <summary>The server id (FK to RustServer; primary key, one row per server).</summary>
public Guid ServerId { get; set; }

Expand Down Expand Up @@ -56,4 +55,7 @@ public sealed class ClanState

/// <summary>When this snapshot was last confirmed (UTC).</summary>
public DateTimeOffset LastSeenUtc { get; set; }

/// <summary>The owning guild snowflake.</summary>
public ulong GuildId { get; set; }
}
10 changes: 6 additions & 4 deletions src/RustPlusBot.Domain/Commands/ServerCommandSettings.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using Persistord.Core.Abstractions;

namespace RustPlusBot.Domain.Commands;

/// <summary>Per-(guild, server) command configuration: trigger prefix and mute state.</summary>
public sealed class ServerCommandSettings
public sealed class ServerCommandSettings : IGuildScoped
{
/// <summary>The owning guild snowflake.</summary>
public ulong GuildId { get; set; }

/// <summary>The server id (FK to RustServer; primary key, one row per server).</summary>
public Guid ServerId { get; set; }

Expand All @@ -14,4 +13,7 @@ public sealed class ServerCommandSettings

/// <summary>Whether all bot-to-game output is currently muted.</summary>
public bool Muted { get; set; }

/// <summary>The owning guild snowflake.</summary>
public ulong GuildId { get; set; }
}
12 changes: 7 additions & 5 deletions src/RustPlusBot.Domain/Connections/ConnectionState.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using Persistord.Core.Abstractions;

namespace RustPlusBot.Domain.Connections;

/// <summary>Persisted last-known connection state per server, so the active identity and status survive restarts.</summary>
public sealed class ConnectionState
public sealed class ConnectionState : IGuildScoped, IUpdatedAt
{
/// <summary>The server this state belongs to (primary key, one row per server).</summary>
public Guid RustServerId { get; set; }

/// <summary>The owning Discord guild snowflake.</summary>
public ulong GuildId { get; set; }

/// <summary>The credential currently selected as active, if any.</summary>
public Guid? ActiveCredentialId { get; set; }

Expand All @@ -18,6 +17,9 @@ public sealed class ConnectionState
/// <summary>Last heartbeat player count, or null if unknown.</summary>
public int? PlayerCount { get; set; }

/// <summary>When the state was last updated (UTC).</summary>
/// <summary>The owning Discord guild snowflake.</summary>
public ulong GuildId { get; set; }

/// <summary>When the state was last updated (UTC). Stamped by Persistord's TimestampInterceptor.</summary>
public DateTimeOffset UpdatedAt { get; set; }
}
12 changes: 7 additions & 5 deletions src/RustPlusBot.Domain/Credentials/FcmRegistration.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
using Persistord.Core.Abstractions;

namespace RustPlusBot.Domain.Credentials;

/// <summary>
/// One Discord user's Rust+ FCM listener registration within a guild. One per (GuildId, OwnerUserId).
/// The credentials blob is stored protected at rest (see ICredentialProtector) and feeds the pairing listener.
/// </summary>
public sealed class FcmRegistration
public sealed class FcmRegistration : IGuildScoped, IUpdatedAt
{
/// <summary>Surrogate primary key.</summary>
public Guid Id { get; set; } = Guid.NewGuid();

/// <summary>The owning Discord guild snowflake.</summary>
public ulong GuildId { get; set; }

/// <summary>The Discord user who connected these credentials.</summary>
public ulong OwnerUserId { get; set; }

Expand All @@ -21,6 +20,9 @@ public sealed class FcmRegistration
/// <summary>Listener lifecycle state.</summary>
public FcmRegistrationStatus Status { get; set; } = FcmRegistrationStatus.Active;

/// <summary>When the registration was last upserted or had its status changed (UTC).</summary>
/// <summary>The owning Discord guild snowflake.</summary>
public ulong GuildId { get; set; }

/// <summary>When the registration was last written (UTC). Stamped by Persistord's TimestampInterceptor.</summary>
public DateTimeOffset UpdatedAt { get; set; }
}
10 changes: 6 additions & 4 deletions src/RustPlusBot.Domain/Credentials/PlayerCredential.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
using Persistord.Core.Abstractions;

namespace RustPlusBot.Domain.Credentials;

/// <summary>
/// One player's Rust+ credentials within a server's pool. Many per (GuildId, RustServerId).
/// The token fields are stored protected at rest (see ICredentialProtector).
/// </summary>
public sealed class PlayerCredential
public sealed class PlayerCredential : IGuildScoped
{
/// <summary>Surrogate primary key.</summary>
public Guid Id { get; set; } = Guid.NewGuid();

/// <summary>The owning Discord guild snowflake.</summary>
public ulong GuildId { get; set; }

/// <summary>The server this credential can connect to.</summary>
public Guid RustServerId { get; set; }

Expand All @@ -26,4 +25,7 @@ public sealed class PlayerCredential

/// <summary>Pool lifecycle state.</summary>
public CredentialStatus Status { get; set; } = CredentialStatus.Standby;

/// <summary>The owning Discord guild snowflake.</summary>
public ulong GuildId { get; set; }
}
15 changes: 8 additions & 7 deletions src/RustPlusBot.Domain/Devices/PairedDeviceEntity.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Persistord.Core.Abstractions;
using RustPlusBot.Abstractions.Connections;

namespace RustPlusBot.Domain.Devices;
Expand All @@ -14,14 +15,11 @@ namespace RustPlusBot.Domain.Devices;
/// type would pull the base into the model and silently collapse both device tables into one
/// table-per-hierarchy table. Each derived device keeps its own table; this base only shares the columns.
/// </remarks>
public abstract class PairedDeviceEntity
public abstract class PairedDeviceEntity : IGuildScoped, ICreatedAt
{
/// <summary>Surrogate primary key.</summary>
public Guid Id { get; set; } = Guid.NewGuid();

/// <summary>The owning Discord guild snowflake.</summary>
public ulong GuildId { get; set; }

/// <summary>The server this device belongs to (FK to RustServer, cascade delete).</summary>
public Guid ServerId { get; set; }

Expand All @@ -37,9 +35,12 @@ public abstract class PairedDeviceEntity
/// <summary>The Discord user who accepted (validated) the pairing.</summary>
public ulong PairedByUserId { get; set; }

/// <summary>When the pairing was accepted (UTC).</summary>
public DateTimeOffset CreatedUtc { get; set; }

/// <summary>Per-device reachability; defaults to Reachable. Orthogonal to whole-server connection status.</summary>
public DeviceReachability Reachability { get; set; } = DeviceReachability.Reachable;

/// <summary>When the pairing was accepted (UTC). Stamped by Persistord's TimestampInterceptor.</summary>
public DateTimeOffset CreatedAt { get; set; }

/// <summary>The owning Discord guild snowflake.</summary>
public ulong GuildId { get; set; }
}
23 changes: 0 additions & 23 deletions src/RustPlusBot.Domain/Entities/PairedEntity.cs

This file was deleted.

17 changes: 0 additions & 17 deletions src/RustPlusBot.Domain/Events/EventSubscription.cs

This file was deleted.

10 changes: 6 additions & 4 deletions src/RustPlusBot.Domain/Guilds/GuildSettings.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
using Persistord.Core.Abstractions;

namespace RustPlusBot.Domain.Guilds;

/// <summary>Per-guild configuration. Primary key is the guild snowflake.</summary>
public sealed class GuildSettings
public sealed class GuildSettings : IGuildScoped
{
/// <summary>The Discord guild snowflake (primary key).</summary>
public ulong GuildId { get; set; }

/// <summary>BCP-47 culture for localized output (e.g. "en", "fr").</summary>
public string Culture { get; set; } = "en";

/// <summary>When true, the server-wiped announcement pings @everyone in #events. Off by default.</summary>
public bool PingEveryoneOnWipe { get; set; }

/// <summary>The Discord guild snowflake (primary key).</summary>
public ulong GuildId { get; set; }
}
9 changes: 5 additions & 4 deletions src/RustPlusBot.Domain/Map/ServerMapSettings.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
using Persistord.Core.Abstractions;
using RustPlusBot.Abstractions.Connections;

namespace RustPlusBot.Domain.Map;

/// <summary>Per-(guild, server) rendered-map layer settings; one row per server. Layers default on.</summary>
public sealed class ServerMapSettings
public sealed class ServerMapSettings : IGuildScoped
{
/// <summary>The owning guild snowflake.</summary>
public ulong GuildId { get; set; }

/// <summary>The server id (FK to RustServer; primary key, one row per server).</summary>
public Guid ServerId { get; set; }

Expand All @@ -34,4 +32,7 @@ public sealed class ServerMapSettings

/// <summary>Which grid convention the rendered map and event grid references use.</summary>
public MapGridStyle GridStyle { get; set; } = MapGridStyle.InGame;

/// <summary>The owning guild snowflake.</summary>
public ulong GuildId { get; set; }
}
7 changes: 7 additions & 0 deletions src/RustPlusBot.Domain/RustPlusBot.Domain.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,11 @@
<ProjectReference Include="..\RustPlusBot.Abstractions\RustPlusBot.Abstractions.csproj" />
</ItemGroup>

<ItemGroup>
<!-- Entities implement Persistord's ICreatedAt/IUpdatedAt and IGuildScoped so the library
stamps timestamps and drives guild scoping. This does pull EF Core in transitively:
the marker interfaces ship inside Persistord.Core, which depends on it. -->
<PackageReference Include="Persistord.Core" />
</ItemGroup>

</Project>
10 changes: 6 additions & 4 deletions src/RustPlusBot.Domain/Servers/RustServer.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using Persistord.Core.Abstractions;

namespace RustPlusBot.Domain.Servers;

/// <summary>A Rust+ server target bound to a Discord guild. Guild-scoped.</summary>
public sealed class RustServer
public sealed class RustServer : IGuildScoped
{
/// <summary>Surrogate primary key.</summary>
public Guid Id { get; set; } = Guid.NewGuid();

/// <summary>The owning Discord guild snowflake.</summary>
public ulong GuildId { get; set; }

/// <summary>Display name shown in Discord.</summary>
public string Name { get; set; } = string.Empty;

Expand All @@ -32,4 +31,7 @@ public sealed class RustServer

/// <summary>Baseline: the last observed world size (game units), or null before first observation.</summary>
public uint? LastMapSize { get; set; }

/// <summary>The owning Discord guild snowflake.</summary>
public ulong GuildId { get; set; }
}
Loading
Loading