Files
RobustToolbox/Robust.Client/Upload/NetworkResourceManager.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

87 lines
2.5 KiB
C#

using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Network.Transfer;
using Robust.Shared.Upload;
using Robust.Shared.Utility;
namespace Robust.Client.Upload;
public sealed class NetworkResourceManager : SharedNetworkResourceManager
{
[Dependency] private readonly IBaseClient _client = default!;
internal override void Initialize()
{
base.Initialize();
_client.RunLevelChanged += OnLevelChanged;
TransferManager.RegisterTransferMessage(TransferKeyNetworkUpload);
TransferManager.RegisterTransferMessage(TransferKeyNetworkDownload, ReceiveDownload);
NetManager.RegisterNetMessage<NetworkResourceAckMessage>();
}
private async void ReceiveDownload(TransferReceivedEvent transfer)
{
Sawmill.Debug("Receiving file download transfer!");
await using var stream = transfer.DataStream;
try
{
var ackKeyBytes = new byte[4];
await stream.ReadExactlyAsync(ackKeyBytes);
var ackKey = BinaryPrimitives.ReadInt32LittleEndian(ackKeyBytes);
await IngestFileStream(stream);
if (ackKey != 0)
{
NetManager.ClientSendMessage(new NetworkResourceAckMessage
{
Key = ackKey
});
}
}
catch (Exception e)
{
Sawmill.Error($"Error while downloading transfer resources: {e}");
}
}
private void OnLevelChanged(object? sender, RunLevelChangedEventArgs e)
{
// Clear networked resources when disconnecting from a multiplayer game.
if (e.OldLevel == ClientRunLevel.InGame)
ClearResources();
}
/// <summary>
/// Clears all the networked resources. If used while connected to a server, this will probably cause issues.
/// </summary>
public void ClearResources()
{
ContentRoot.Clear();
}
internal async void UploadResources(List<(ResPath Relative, byte[] Data)> files)
{
var clientNet = (IClientNetManager)NetManager;
if (clientNet.ServerChannel is not { } channel)
throw new InvalidOperationException("Not connected to server!");
await using var transfer = TransferManager.StartTransfer(
channel,
new TransferStartInfo
{
MessageKey = TransferKeyNetworkUpload,
});
await WriteFileStream(transfer, files);
}
}