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
2 changes: 2 additions & 0 deletions Common/Constants/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,7 @@ public static class Duration
public static readonly TimeSpan DeviceKeepAliveInitialTimeout = TimeSpan.FromSeconds(65);
public static readonly TimeSpan DeviceKeepAliveTimeout = TimeSpan.FromSeconds(35);

public static readonly TimeSpan HubControlMaxQueueAge = TimeSpan.FromSeconds(5);

public static readonly TimeSpan DeactivatedAccountRetentionTime = TimeSpan.FromDays(14);
}
34 changes: 32 additions & 2 deletions Common/Websocket/WebsockBaseController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Net.WebSockets;
using System.Diagnostics;
using System.Net.WebSockets;
using System.Text.Json;
using System.Threading.Channels;
using Microsoft.AspNetCore.Mvc;
Expand Down Expand Up @@ -45,7 +46,12 @@ public abstract class WebsocketBaseController<T> : OpenShockControllerBase, IAsy
/// <summary>
/// A message waiting to be sent, <paramref name="Sent"/> is completed with whether it was written to the websocket
/// </summary>
protected readonly record struct QueuedMessage(T Data, TaskCompletionSource<bool>? Sent);
/// <param name="Data"></param>
/// <param name="Sent"></param>
/// <param name="ExpiresAt">
/// <see cref="Stopwatch.GetTimestamp"/> after which the message is dropped instead of written, 0 for never.
/// </param>
protected readonly record struct QueuedMessage(T Data, TaskCompletionSource<bool>? Sent, long ExpiresAt = 0);

#pragma warning disable IDISP008
protected WebSocket? WebSocket;
Expand Down Expand Up @@ -73,6 +79,23 @@ public ValueTask QueueMessage(T data)
return Channel.Writer.WriteAsync(new QueuedMessage(data, null), LinkedToken);
}

/// <summary>
/// Queue a message that is only worth sending promptly. If the client is so far behind that it has
/// waited longer than <paramref name="maxQueueAge"/> when its turn comes, it is dropped.
/// </summary>
[NonAction]
public ValueTask QueueMessage(T data, TimeSpan maxQueueAge)
{
if (!CanSend())
{
Logger.LogDebug("WebSocket is null, abort or closed, not sending message");
return ValueTask.CompletedTask;
}

var expiresAt = Stopwatch.GetTimestamp() + (long)(maxQueueAge.TotalSeconds * Stopwatch.Frequency);
return Channel.Writer.WriteAsync(new QueuedMessage(data, null, expiresAt), LinkedToken);
}

/// <summary>
/// Queue a message and wait until it has been written to the websocket
/// </summary>
Expand Down Expand Up @@ -207,6 +230,13 @@ private async Task MessageLoop()
{
await foreach (var msg in Channel.Reader.ReadAllAsync(LinkedToken))
{
if (msg.ExpiresAt != 0 && Stopwatch.GetTimestamp() > msg.ExpiresAt)
{
Logger.LogDebug("Dropping a message that waited too long in the send queue");
msg.Sent?.TrySetResult(false);
continue;
}

try
{
await SendWebSocketMessage(msg.Data, WebSocket!, LinkedToken);
Expand Down
3 changes: 2 additions & 1 deletion LiveControlGateway/Controllers/HubV1Controller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using OpenShock.Common.Authentication;
using OpenShock.Common.Constants;
using OpenShock.Common.Hubs;
using OpenShock.Common.Models;
using OpenShock.Common.OpenShockDb;
Expand Down Expand Up @@ -172,7 +173,7 @@ await otaService.Error(CurrentHubId, payload.BootStatus.OtaUpdateId, false,
/// <inheritdoc />
[NonAction]
public override ValueTask Control(IList<ShockerCommand> controlCommands)
=> QueueMessage(ControlMessage(controlCommands));
=> QueueMessage(ControlMessage(controlCommands), Duration.HubControlMaxQueueAge);

/// <inheritdoc />
[NonAction]
Expand Down
2 changes: 1 addition & 1 deletion LiveControlGateway/Controllers/HubV2Controller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ await otaService.Error(CurrentHubId, payload.BootStatus.OtaUpdateId, false,

/// <inheritdoc />
public override ValueTask Control(IList<ShockerCommand> controlCommands)
=> QueueMessage(ControlMessage(controlCommands));
=> QueueMessage(ControlMessage(controlCommands), Duration.HubControlMaxQueueAge);

/// <inheritdoc />
public override Task<bool> SendControl(IList<ShockerCommand> controlCommands)
Expand Down
Loading