Files
RobustToolbox/Robust.Shared/Network/Transfer/BaseTransferManager.Lidgren.cs
Pieter-Jan Briers dc1464b462 High-bandwidth transfer system (#6373)
* WebSocket-based data transfer system

* Move resource downloads/uploads to the new transfer system

Should drastically increase the permitted practical size

* Transfer impl for Lidgren

* Async impl for receive stream

* Use unbounded channel for Lidgren

* Add metrics

* More comments

* Add serverside stream limit to avoid being a DoS vector

* Fix tests

* Oops forgot to actually implement sequence channels in NetMessage

* Doc comment for NetMessage.SequenceChannel

* Release notes
2026-01-19 20:44:44 +01:00

68 lines
2.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Robust.Shared.Collections;
using Robust.Shared.Network.Messages.Transfer;
namespace Robust.Shared.Network.Transfer;
internal abstract partial class BaseTransferManager
{
private readonly Lock _waitingSendChannelLock = new();
private readonly Dictionary<INetChannel, TaskCompletionSource> _waitingSendChannels = [];
private ValueList<(INetChannel, TaskCompletionSource)> _sendChannelQueue;
public void FrameUpdate()
{
lock (_waitingSendChannelLock)
{
foreach (var (channel, tcs) in _waitingSendChannels)
{
if (!channel.IsConnected || SendCheck(channel))
_sendChannelQueue.Add((channel, tcs));
}
// Remove BEFORE dispatching any TCSes, so we don't try to add to the list from a callback.
foreach (var (channel, _) in _sendChannelQueue)
{
_waitingSendChannels.Remove(channel);
}
}
foreach (var (channel, tcs) in _sendChannelQueue)
{
if (!channel.IsConnected)
tcs.TrySetException(new NetChannelClosedException("Channel closed"));
else
tcs.TrySetResult();
}
_sendChannelQueue.Clear();
}
public async ValueTask WaitToSend(INetChannel channel)
{
if (SendCheck(channel))
return;
TaskCompletionSource tcs;
lock (_waitingSendChannelLock)
{
ref var tcsSlot = ref CollectionsMarshal.GetValueRefOrAddDefault(_waitingSendChannels, channel, out _);
tcsSlot ??= new TaskCompletionSource();
tcs = tcsSlot;
}
await tcs.Task;
}
private static bool SendCheck(INetChannel channel)
{
return channel.CanSendImmediately(MsgTransferData.Method, MsgTransferData.Channel);
}
private sealed class NetChannelClosedException(string message) : Exception(message);
}