Skip to content

Commit 6adc38c

Browse files
HandyS11claude
andcommitted
feat(devices): persist per-device Reachability (+ migration, store mutators)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 9d87461 commit 6adc38c

18 files changed

Lines changed: 942 additions & 0 deletions

src/RustPlusBot.Domain/Alarms/SmartAlarm.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using RustPlusBot.Abstractions.Connections;
2+
13
namespace RustPlusBot.Domain.Alarms;
24

35
/// <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>
@@ -38,4 +40,7 @@ public sealed class SmartAlarm
3840

3941
/// <summary>When the alarm most recently went active (UTC), or null if never triggered.</summary>
4042
public DateTimeOffset? LastTriggeredUtc { get; set; }
43+
44+
/// <summary>Per-device reachability; defaults to Reachable. Orthogonal to whole-server connection status.</summary>
45+
public DeviceReachability Reachability { get; set; } = DeviceReachability.Reachable;
4146
}

src/RustPlusBot.Domain/StorageMonitors/SmartStorageMonitor.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using RustPlusBot.Abstractions.Connections;
2+
13
namespace RustPlusBot.Domain.StorageMonitors;
24

35
/// <summary>A paired Smart Storage Monitor the bot manages, surviving restarts. Guild- and server-scoped.</summary>
@@ -26,4 +28,7 @@ public sealed class SmartStorageMonitor
2628

2729
/// <summary>When the monitor was accepted (UTC).</summary>
2830
public DateTimeOffset CreatedUtc { get; set; }
31+
32+
/// <summary>Per-device reachability; defaults to Reachable. Orthogonal to whole-server connection status.</summary>
33+
public DeviceReachability Reachability { get; set; } = DeviceReachability.Reachable;
2934
}

src/RustPlusBot.Domain/Switches/SmartSwitch.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using RustPlusBot.Abstractions.Connections;
2+
13
namespace RustPlusBot.Domain.Switches;
24

35
/// <summary>A paired Smart Switch the bot manages, surviving restarts. Guild- and server-scoped.</summary>
@@ -29,4 +31,7 @@ public sealed class SmartSwitch
2931

3032
/// <summary>When the switch was accepted (UTC).</summary>
3133
public DateTimeOffset CreatedUtc { get; set; }
34+
35+
/// <summary>Per-device reachability; defaults to Reachable. Orthogonal to whole-server connection status.</summary>
36+
public DeviceReachability Reachability { get; set; } = DeviceReachability.Reachable;
3237
}

src/RustPlusBot.Persistence/Alarms/AlarmStore.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Microsoft.EntityFrameworkCore;
2+
using RustPlusBot.Abstractions.Connections;
23
using RustPlusBot.Abstractions.Time;
34
using RustPlusBot.Domain.Alarms;
45

@@ -136,6 +137,15 @@ public Task UpdateStateAsync(
136137
}
137138
}, ct);
138139

140+
/// <inheritdoc />
141+
public Task SetReachabilityAsync(
142+
ulong guildId,
143+
Guid serverId,
144+
ulong entityId,
145+
DeviceReachability reachability,
146+
CancellationToken ct = default) =>
147+
MutateAsync(guildId, serverId, entityId, a => a.Reachability = reachability, ct);
148+
139149
/// <inheritdoc />
140150
public async Task RemoveAsync(
141151
ulong guildId,

src/RustPlusBot.Persistence/Alarms/IAlarmStore.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using RustPlusBot.Abstractions.Connections;
12
using RustPlusBot.Domain.Alarms;
23

34
namespace RustPlusBot.Persistence.Alarms;
@@ -127,6 +128,20 @@ Task UpdateStateAsync(
127128
DateTimeOffset? triggeredUtc,
128129
CancellationToken ct = default);
129130

131+
/// <summary>Sets a device's reachability (no-op if absent).</summary>
132+
/// <param name="guildId">Owning Discord guild snowflake.</param>
133+
/// <param name="serverId">The Rust server id.</param>
134+
/// <param name="entityId">The in-game smart-alarm entity id.</param>
135+
/// <param name="reachability">The new reachability value.</param>
136+
/// <param name="ct">A cancellation token.</param>
137+
/// <returns>A task that completes when the reachability has been persisted.</returns>
138+
Task SetReachabilityAsync(
139+
ulong guildId,
140+
Guid serverId,
141+
ulong entityId,
142+
DeviceReachability reachability,
143+
CancellationToken ct = default);
144+
130145
/// <summary>Removes an alarm (no-op if absent).</summary>
131146
/// <param name="guildId">Owning Discord guild snowflake.</param>
132147
/// <param name="serverId">The Rust server id.</param>

src/RustPlusBot.Persistence/Configurations/SmartAlarmConfiguration.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.EntityFrameworkCore;
22
using Microsoft.EntityFrameworkCore.Metadata.Builders;
3+
using RustPlusBot.Abstractions.Connections;
34
using RustPlusBot.Domain.Alarms;
45
using RustPlusBot.Domain.Servers;
56

@@ -17,6 +18,10 @@ public void Configure(EntityTypeBuilder<SmartAlarm> builder)
1718
a.GuildId, a.ServerId, a.EntityId
1819
}).IsUnique();
1920

21+
builder.Property(a => a.Reachability)
22+
.HasConversion<int>()
23+
.HasDefaultValue(DeviceReachability.Reachable);
24+
2025
// Removing a RustServer cascades to its alarms so no orphaned rows linger.
2126
builder.HasOne<RustServer>()
2227
.WithMany()

src/RustPlusBot.Persistence/Configurations/SmartStorageMonitorConfiguration.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.EntityFrameworkCore;
22
using Microsoft.EntityFrameworkCore.Metadata.Builders;
3+
using RustPlusBot.Abstractions.Connections;
34
using RustPlusBot.Domain.Servers;
45
using RustPlusBot.Domain.StorageMonitors;
56

@@ -17,6 +18,10 @@ public void Configure(EntityTypeBuilder<SmartStorageMonitor> builder)
1718
s.GuildId, s.ServerId, s.EntityId
1819
}).IsUnique();
1920

21+
builder.Property(s => s.Reachability)
22+
.HasConversion<int>()
23+
.HasDefaultValue(DeviceReachability.Reachable);
24+
2025
// Removing a RustServer cascades to its storage monitors so no orphaned rows linger.
2126
builder.HasOne<RustServer>()
2227
.WithMany()

src/RustPlusBot.Persistence/Configurations/SmartSwitchConfiguration.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.EntityFrameworkCore;
22
using Microsoft.EntityFrameworkCore.Metadata.Builders;
3+
using RustPlusBot.Abstractions.Connections;
34
using RustPlusBot.Domain.Servers;
45
using RustPlusBot.Domain.Switches;
56

@@ -17,6 +18,10 @@ public void Configure(EntityTypeBuilder<SmartSwitch> builder)
1718
s.GuildId, s.ServerId, s.EntityId
1819
}).IsUnique();
1920

21+
builder.Property(s => s.Reachability)
22+
.HasConversion<int>()
23+
.HasDefaultValue(DeviceReachability.Reachable);
24+
2025
// Removing a RustServer cascades to its switches so no orphaned rows linger.
2126
builder.HasOne<RustServer>()
2227
.WithMany()

0 commit comments

Comments
 (0)