Move upload commands to engine (#16582)

This commit is contained in:
Leon Friedrich
2023-05-20 13:53:09 +12:00
committed by GitHub
parent 8422e51678
commit be0d22ad5e
20 changed files with 43 additions and 590 deletions

View File

@@ -1,33 +0,0 @@
using System.IO;
using Content.Shared.Administration;
using Robust.Client.UserInterface;
using Robust.Shared.Console;
namespace Content.Client.Administration.Commands;
public sealed class LoadPrototypeCommand : IConsoleCommand
{
public string Command { get; } = "loadprototype";
public string Description { get; } = "Load a prototype file into the server.";
public string Help => Command;
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
LoadPrototype();
}
public static async void LoadPrototype()
{
var dialogManager = IoCManager.Resolve<IFileDialogManager>();
var loadManager = IoCManager.Resolve<IGamePrototypeLoadManager>();
var stream = await dialogManager.OpenFile();
if (stream is null)
return;
// ew oop
var reader = new StreamReader(stream);
var proto = await reader.ReadToEndAsync();
loadManager.SendGamePrototype(proto);
}
}

View File

@@ -1,64 +0,0 @@
using Content.Shared.Administration;
using Content.Shared.CCVar;
using Robust.Client.UserInterface;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
using Robust.Shared.Network;
using Robust.Shared.Utility;
namespace Content.Client.Administration.Commands;
public sealed class UploadFile : IConsoleCommand
{
public string Command => "uploadfile";
public string Description => "Uploads a resource to the server.";
public string Help => $"{Command} [relative path for the resource]";
public async void Execute(IConsoleShell shell, string argStr, string[] args)
{
var cfgMan = IoCManager.Resolve<IConfigurationManager>();
if (!cfgMan.GetCVar(CCVars.ResourceUploadingEnabled))
{
shell.WriteError("Network Resource Uploading is currently disabled by the server.");
return;
}
if (args.Length != 1)
{
shell.WriteError("Wrong number of arguments!");
return;
}
var path = new ResPath(args[0]).ToRelativePath();
var dialog = IoCManager.Resolve<IFileDialogManager>();
var filters = new FileDialogFilters(new FileDialogFilters.Group(path.Extension));
await using var file = await dialog.OpenFile(filters);
if (file == null)
{
shell.WriteError("Error picking file!");
return;
}
var sizeLimit = cfgMan.GetCVar(CCVars.ResourceUploadingLimitMb);
if (sizeLimit > 0f && file.Length * SharedNetworkResourceManager.BytesToMegabytes > sizeLimit)
{
shell.WriteError($"File above the current size limit! It must be smaller than {sizeLimit} MB.");
return;
}
var data = file.CopyToArray();
var netManager = IoCManager.Resolve<INetManager>();
var msg = netManager.CreateNetMessage<NetworkResourceUploadMessage>();
msg.RelativePath = path;
msg.Data = data;
netManager.ClientSendMessage(msg);
}
}

View File

@@ -1,76 +0,0 @@
using System.IO;
using Content.Shared.Administration;
using Content.Shared.CCVar;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
using Robust.Shared.ContentPack;
using Robust.Shared.Network;
using Robust.Shared.Utility;
namespace Content.Client.Administration.Commands;
public sealed class UploadFolder : IConsoleCommand
{
public string Command => "uploadfolder";
public string Description => Loc.GetString("uploadfolder-command-description");
public string Help => Loc.GetString("uploadfolder-command-help");
private static readonly ResPath BaseUploadFolderPath = new("/UploadFolder");
[Dependency] private IResourceManager _resourceManager = default!;
[Dependency] private IConfigurationManager _configManager = default!;
public async void Execute(IConsoleShell shell, string argStr, string[] args)
{
var fileCount = 0;
if (!_configManager.GetCVar(CCVars.ResourceUploadingEnabled))
{
shell.WriteError( Loc.GetString("uploadfolder-command-resource-upload-disabled"));
return;
}
if (args.Length != 1)
{
shell.WriteError( Loc.GetString("uploadfolder-command-wrong-args"));
shell.WriteLine( Loc.GetString("uploadfolder-command-help"));
return;
}
var folderPath = new ResPath(BaseUploadFolderPath + $"/{args[0]}");
if (!_resourceManager.UserData.Exists(folderPath.ToRootedPath()))
{
shell.WriteError( Loc.GetString("uploadfolder-command-folder-not-found",("folder", folderPath)));
return; // bomb out if the folder doesnt exist in /UploadFolder
}
//Grab all files in specified folder and upload them
foreach (var filepath in _resourceManager.UserData.Find($"{folderPath.ToRelativePath()}/").files )
{
await using var filestream = _resourceManager.UserData.Open(filepath,FileMode.Open);
{
var sizeLimit = _configManager.GetCVar(CCVars.ResourceUploadingLimitMb);
if (sizeLimit > 0f && filestream.Length * SharedNetworkResourceManager.BytesToMegabytes > sizeLimit)
{
shell.WriteError( Loc.GetString("uploadfolder-command-file-too-big", ("filename",filepath), ("sizeLimit",sizeLimit)));
return;
}
var data = filestream.CopyToArray();
var netManager = IoCManager.Resolve<INetManager>();
var msg = netManager.CreateNetMessage<NetworkResourceUploadMessage>();
msg.RelativePath = new ResPath($"{filepath.ToString().Remove(0,14)}"); //removes /UploadFolder/ from path
msg.Data = data;
netManager.ClientSendMessage(msg);
fileCount++;
}
}
shell.WriteLine( Loc.GetString("uploadfolder-command-success",("fileCount",fileCount)));
}
}

View File

@@ -1,36 +0,0 @@
using Content.Shared.Administration;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
namespace Content.Client.Administration.Managers;
public sealed class GamePrototypeLoadManager : IGamePrototypeLoadManager
{
[Dependency] private readonly IClientNetManager _netManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly ILocalizationManager _localizationManager = default!;
public void Initialize()
{
_netManager.RegisterNetMessage<GamePrototypeLoadMessage>(LoadGamePrototype);
}
private void LoadGamePrototype(GamePrototypeLoadMessage message)
{
var changed = new Dictionary<Type, HashSet<string>>();
_prototypeManager.LoadString(message.PrototypeData, true, changed);
_prototypeManager.ResolveResults();
_prototypeManager.ReloadPrototypes(changed);
_localizationManager.ReloadLocalizations();
Logger.InfoS("adminbus", "Loaded adminbus prototype data.");
}
public void SendGamePrototype(string prototype)
{
var msg = new GamePrototypeLoadMessage
{
PrototypeData = prototype
};
_netManager.ClientSendMessage(msg);
}
}

View File

@@ -1,15 +0,0 @@
using Content.Shared.Administration;
namespace Content.Client.Administration.Managers;
public sealed class NetworkResourceManager : SharedNetworkResourceManager
{
/// <summary>
/// Callback for when the server sends a new resource.
/// </summary>
/// <param name="msg">The network message containing the data.</param>
protected override void ResourceUploadMsg(NetworkResourceUploadMessage msg)
{
ContentRoot.AddOrUpdateFile(msg.RelativePath, msg.Data);
}
}

View File

@@ -1,9 +1,8 @@
using System.IO; using Content.Client.Administration.Managers;
using Content.Client.Administration.Commands;
using Content.Client.Administration.Managers;
using Content.Client.UserInterface.Systems.DecalPlacer; using Content.Client.UserInterface.Systems.DecalPlacer;
using Content.Shared.Administration; using Content.Shared.Administration;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.Upload.Commands;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers.Implementations; using Robust.Client.UserInterface.Controllers.Implementations;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;

View File

@@ -52,14 +52,11 @@ namespace Content.Client.Entry
[Dependency] private readonly ViewportManager _viewportManager = default!; [Dependency] private readonly ViewportManager _viewportManager = default!;
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!; [Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!; [Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IOverlayManager _overlayManager = default!; [Dependency] private readonly IOverlayManager _overlayManager = default!;
[Dependency] private readonly IChatManager _chatManager = default!; [Dependency] private readonly IChatManager _chatManager = default!;
[Dependency] private readonly IClientPreferencesManager _clientPreferencesManager = default!; [Dependency] private readonly IClientPreferencesManager _clientPreferencesManager = default!;
[Dependency] private readonly EuiManager _euiManager = default!; [Dependency] private readonly EuiManager _euiManager = default!;
[Dependency] private readonly IVoteManager _voteManager = default!; [Dependency] private readonly IVoteManager _voteManager = default!;
[Dependency] private readonly IGamePrototypeLoadManager _gamePrototypeLoadManager = default!;
[Dependency] private readonly NetworkResourceManager _networkResources = default!;
[Dependency] private readonly DocumentParsingManager _documentParsingManager = default!; [Dependency] private readonly DocumentParsingManager _documentParsingManager = default!;
[Dependency] private readonly GhostKickManager _ghostKick = default!; [Dependency] private readonly GhostKickManager _ghostKick = default!;
[Dependency] private readonly ExtendedDisconnectInformationManager _extendedDisconnectInformation = default!; [Dependency] private readonly ExtendedDisconnectInformationManager _extendedDisconnectInformation = default!;
@@ -162,8 +159,6 @@ namespace Content.Client.Entry
_clientPreferencesManager.Initialize(); _clientPreferencesManager.Initialize();
_euiManager.Initialize(); _euiManager.Initialize();
_voteManager.Initialize(); _voteManager.Initialize();
_gamePrototypeLoadManager.Initialize();
_networkResources.Initialize();
_userInterfaceManager.SetDefaultTheme("SS14DefaultTheme"); _userInterfaceManager.SetDefaultTheme("SS14DefaultTheme");
_documentParsingManager.Initialize(); _documentParsingManager.Initialize();

View File

@@ -39,8 +39,6 @@ namespace Content.Client.IoC
IoCManager.Register<ChangelogManager, ChangelogManager>(); IoCManager.Register<ChangelogManager, ChangelogManager>();
IoCManager.Register<RulesManager, RulesManager>(); IoCManager.Register<RulesManager, RulesManager>();
IoCManager.Register<ViewportManager, ViewportManager>(); IoCManager.Register<ViewportManager, ViewportManager>();
IoCManager.Register<IGamePrototypeLoadManager, GamePrototypeLoadManager>();
IoCManager.Register<NetworkResourceManager>();
IoCManager.Register<ISharedAdminLogManager, SharedAdminLogManager>(); IoCManager.Register<ISharedAdminLogManager, SharedAdminLogManager>();
IoCManager.Register<GhostKickManager>(); IoCManager.Register<GhostKickManager>();
IoCManager.Register<ExtendedDisconnectInformationManager>(); IoCManager.Register<ExtendedDisconnectInformationManager>();

View File

@@ -0,0 +1,36 @@
using Content.Server.Database;
using Content.Shared.CCVar;
using Robust.Server.Player;
using Robust.Server.Upload;
using Robust.Shared.Configuration;
using Robust.Shared.Upload;
namespace Content.Server.Administration;
public sealed class ContentNetworkResourceManager
{
[Dependency] private readonly IServerDbManager _serverDb = default!;
[Dependency] private readonly NetworkResourceManager _netRes = default!;
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
[ViewVariables] public bool StoreUploaded { get; set; } = true;
public void Initialize()
{
_cfgManager.OnValueChanged(CCVars.ResourceUploadingStoreEnabled, value => StoreUploaded = value, true);
AutoDelete(_cfgManager.GetCVar(CCVars.ResourceUploadingStoreDeletionDays));
_netRes.OnResourceUploaded += OnUploadResource;
}
private async void OnUploadResource(IPlayerSession session, NetworkResourceUploadMessage msg)
{
if (StoreUploaded)
await _serverDb.AddUploadedResourceLogAsync(session.UserId, DateTime.Now, msg.RelativePath.ToString(), msg.Data);
}
private async void AutoDelete(int days)
{
if (days > 0)
await _serverDb.PurgeUploadedResourceLogAsync(days);
}
}

View File

@@ -1,91 +0,0 @@
using Content.Server.Administration.Managers;
using Content.Shared.Administration;
using Robust.Server.Player;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Replays;
using Robust.Shared.Serialization.Markdown.Mapping;
namespace Content.Server.Administration;
/// <summary>
/// Manages sending runtime-loaded prototypes from game staff to clients.
/// </summary>
public sealed class GamePrototypeLoadManager : IGamePrototypeLoadManager
{
[Dependency] private readonly IReplayRecordingManager _replay = default!;
[Dependency] private readonly IServerNetManager _netManager = default!;
[Dependency] private readonly IAdminManager _adminManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly ILocalizationManager _localizationManager = default!;
private readonly List<string> _loadedPrototypes = new();
public IReadOnlyList<string> LoadedPrototypes => _loadedPrototypes;
public void Initialize()
{
_netManager.RegisterNetMessage<GamePrototypeLoadMessage>(ClientLoadsPrototype);
_netManager.Connected += NetManagerOnConnected;
_replay.OnRecordingStarted += OnStartReplayRecording;
}
private void OnStartReplayRecording((MappingDataNode, List<object>) initReplayData)
{
// replays will need information about currently loaded prototypes
foreach (var prototype in _loadedPrototypes)
{
initReplayData.Item2.Add(new ReplayPrototypeUploadMsg { PrototypeData = prototype });
}
}
public void SendGamePrototype(string prototype)
{
}
private void ClientLoadsPrototype(GamePrototypeLoadMessage message)
{
var player = _playerManager.GetSessionByChannel(message.MsgChannel);
if (_adminManager.IsAdmin(player) && _adminManager.HasAdminFlag(player, AdminFlags.Query))
{
LoadPrototypeData(message.PrototypeData);
Logger.InfoS("adminbus", $"Loaded adminbus prototype data from {player.Name}.");
}
else
{
message.MsgChannel.Disconnect("Sent prototype message without permission!");
}
}
private void LoadPrototypeData(string prototypeData)
{
_loadedPrototypes.Add(prototypeData);
_replay.QueueReplayMessage(new ReplayPrototypeUploadMsg { PrototypeData = prototypeData });
var msg = new GamePrototypeLoadMessage
{
PrototypeData = prototypeData
};
_netManager.ServerSendToAll(msg); // everyone load it up!
var changed = new Dictionary<Type, HashSet<string>>();
_prototypeManager.LoadString(prototypeData, true, changed); // server needs it too.
_prototypeManager.ResolveResults();
_prototypeManager.ReloadPrototypes(changed);
_localizationManager.ReloadLocalizations();
}
private void NetManagerOnConnected(object? sender, NetChannelArgs e)
{
// Just dump all the prototypes on connect, before them missing could be an issue.
foreach (var prototype in _loadedPrototypes)
{
var msg = new GamePrototypeLoadMessage
{
PrototypeData = prototype
};
e.Channel.SendMessage(msg);
}
}
}

View File

@@ -1,105 +0,0 @@
using Content.Server.Administration.Managers;
using Content.Server.Database;
using Content.Shared.Administration;
using Content.Shared.CCVar;
using Robust.Server.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
using Robust.Shared.Replays;
using Robust.Shared.Serialization.Markdown.Mapping;
namespace Content.Server.Administration;
public sealed class NetworkResourceManager : SharedNetworkResourceManager
{
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IAdminManager _adminManager = default!;
[Dependency] private readonly IServerNetManager _serverNetManager = default!;
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
[Dependency] private readonly IServerDbManager _serverDb = default!;
[Dependency] private readonly IReplayRecordingManager _replay = default!;
[ViewVariables] public bool Enabled { get; private set; } = true;
[ViewVariables] public float SizeLimit { get; private set; } = 0f;
[ViewVariables] public bool StoreUploaded { get; set; } = true;
public override void Initialize()
{
base.Initialize();
_serverNetManager.Connected += ServerNetManagerOnConnected;
_cfgManager.OnValueChanged(CCVars.ResourceUploadingEnabled, value => Enabled = value, true);
_cfgManager.OnValueChanged(CCVars.ResourceUploadingLimitMb, value => SizeLimit = value, true);
_cfgManager.OnValueChanged(CCVars.ResourceUploadingStoreEnabled, value => StoreUploaded = value, true);
AutoDelete(_cfgManager.GetCVar(CCVars.ResourceUploadingStoreDeletionDays));
_replay.OnRecordingStarted += OnStartReplayRecording;
}
private void OnStartReplayRecording((MappingDataNode, List<object>) initReplayData)
{
// replays will need information about currently loaded extra resources
foreach (var (path, data) in ContentRoot.GetAllFiles())
{
initReplayData.Item2.Add(new ReplayResourceUploadMsg { RelativePath = path, Data = data });
}
}
/// <summary>
/// Callback for when a client attempts to upload a resource.
/// </summary>
/// <param name="msg"></param>
/// <exception cref="NotImplementedException"></exception>
protected override async void ResourceUploadMsg(NetworkResourceUploadMessage msg)
{
// Do not allow uploading any new resources if it has been disabled.
// Note: Any resources uploaded before being disabled will still be kept and sent.
if (!Enabled)
return;
if (!_playerManager.TryGetSessionByChannel(msg.MsgChannel, out var session))
return;
// +QUERY only for now.
if (!_adminManager.HasAdminFlag(session, AdminFlags.Query))
return;
// Ensure the data is under the current size limit, if it's currently enabled.
if (SizeLimit > 0f && msg.Data.Length * BytesToMegabytes > SizeLimit)
return;
ContentRoot.AddOrUpdateFile(msg.RelativePath, msg.Data);
// Now we broadcast the message!
foreach (var channel in _serverNetManager.Channels)
{
channel.SendMessage(msg);
}
_replay.QueueReplayMessage(new ReplayResourceUploadMsg { RelativePath = msg.RelativePath, Data = msg.Data });
if (!StoreUploaded)
return;
await _serverDb.AddUploadedResourceLogAsync(session.UserId, DateTime.Now, msg.RelativePath.ToString(), msg.Data);
}
private void ServerNetManagerOnConnected(object? sender, NetChannelArgs e)
{
foreach (var (path, data) in ContentRoot.GetAllFiles())
{
var msg = new NetworkResourceUploadMessage();
msg.RelativePath = path;
msg.Data = data;
e.Channel.SendMessage(msg);
}
}
private async void AutoDelete(int days)
{
if (days <= 0)
return; // auto-deletion disabled...
await _serverDb.PurgeUploadedResourceLogAsync(days);
}
}

View File

@@ -105,8 +105,7 @@ namespace Content.Server.Entry
_dbManager.Init(); _dbManager.Init();
IoCManager.Resolve<IServerPreferencesManager>().Init(); IoCManager.Resolve<IServerPreferencesManager>().Init();
IoCManager.Resolve<INodeGroupFactory>().Initialize(); IoCManager.Resolve<INodeGroupFactory>().Initialize();
IoCManager.Resolve<IGamePrototypeLoadManager>().Initialize(); IoCManager.Resolve<ContentNetworkResourceManager>().Initialize();
IoCManager.Resolve<NetworkResourceManager>().Initialize();
IoCManager.Resolve<GhostKickManager>().Initialize(); IoCManager.Resolve<GhostKickManager>().Initialize();
IoCManager.Resolve<ServerInfoManager>().Initialize(); IoCManager.Resolve<ServerInfoManager>().Initialize();

View File

@@ -20,7 +20,6 @@ using Content.Server.ServerInfo;
using Content.Server.ServerUpdates; using Content.Server.ServerUpdates;
using Content.Server.Voting.Managers; using Content.Server.Voting.Managers;
using Content.Server.Worldgen.Tools; using Content.Server.Worldgen.Tools;
using Content.Shared.Administration;
using Content.Shared.Administration.Logs; using Content.Shared.Administration.Logs;
using Content.Shared.Administration.Managers; using Content.Shared.Administration.Managers;
using Content.Shared.Kitchen; using Content.Shared.Kitchen;
@@ -48,10 +47,9 @@ namespace Content.Server.IoC
IoCManager.Register<IPlayerLocator, PlayerLocator>(); IoCManager.Register<IPlayerLocator, PlayerLocator>();
IoCManager.Register<IAfkManager, AfkManager>(); IoCManager.Register<IAfkManager, AfkManager>();
IoCManager.Register<IGameMapManager, GameMapManager>(); IoCManager.Register<IGameMapManager, GameMapManager>();
IoCManager.Register<IGamePrototypeLoadManager, GamePrototypeLoadManager>();
IoCManager.Register<RulesManager, RulesManager>(); IoCManager.Register<RulesManager, RulesManager>();
IoCManager.Register<RoleBanManager, RoleBanManager>(); IoCManager.Register<RoleBanManager, RoleBanManager>();
IoCManager.Register<NetworkResourceManager>(); IoCManager.Register<ContentNetworkResourceManager>();
IoCManager.Register<IAdminNotesManager, AdminNotesManager>(); IoCManager.Register<IAdminNotesManager, AdminNotesManager>();
IoCManager.Register<GhostKickManager>(); IoCManager.Register<GhostKickManager>();
IoCManager.Register<ISharedAdminLogManager, AdminLogManager>(); IoCManager.Register<ISharedAdminLogManager, AdminLogManager>();

View File

@@ -1,22 +0,0 @@
using Lidgren.Network;
using Robust.Shared.Network;
using Robust.Shared.Serialization;
namespace Content.Shared.Administration;
public sealed class GamePrototypeLoadMessage : NetMessage
{
public override MsgGroups MsgGroup => MsgGroups.String;
public string PrototypeData { get; set; } = string.Empty;
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
{
PrototypeData = buffer.ReadString();
}
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
{
buffer.Write(PrototypeData);
}
}

View File

@@ -1,19 +0,0 @@
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
namespace Content.Shared.Administration;
public interface IGamePrototypeLoadManager
{
public void Initialize();
public void SendGamePrototype(string prototype);
}
// TODO REPLAYS
// Figure out a way to just directly save NetMessage objects to replays. This just uses IRobustSerializer as a crutch.
[Serializable, NetSerializable]
public sealed class ReplayPrototypeUploadMsg
{
public string PrototypeData = default!;
}

View File

@@ -1,41 +0,0 @@
using Lidgren.Network;
using Robust.Shared.Network;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
namespace Content.Shared.Administration;
public sealed class NetworkResourceUploadMessage : NetMessage
{
public override NetDeliveryMethod DeliveryMethod => NetDeliveryMethod.ReliableUnordered;
public override MsgGroups MsgGroup => MsgGroups.Command;
public byte[] Data { get; set; } = Array.Empty<byte>();
public ResPath RelativePath { get; set; } = ResPath.Self;
public NetworkResourceUploadMessage()
{
}
public NetworkResourceUploadMessage(byte[] data, ResPath relativePath)
{
Data = data;
RelativePath = relativePath;
}
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
{
var dataLength = buffer.ReadVariableInt32();
Data = buffer.ReadBytes(dataLength);
// What is the second argument here?
RelativePath = new ResPath(buffer.ReadString());
}
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
{
buffer.WriteVariableInt32(Data.Length);
buffer.Write(Data);
buffer.Write(RelativePath.ToString());
buffer.Write(ResPath.Separator);
}
}

View File

@@ -1,52 +0,0 @@
using Robust.Shared.ContentPack;
using Robust.Shared.Network;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
namespace Content.Shared.Administration;
/// <summary>
/// Manager that allows resources to be added at runtime by admins.
/// They will be sent to all clients automatically.
/// </summary>
public abstract class SharedNetworkResourceManager : IDisposable
{
[Dependency] private readonly INetManager _netManager = default!;
[Dependency] protected readonly IResourceManager ResourceManager = default!;
public const double BytesToMegabytes = 0.000001d;
/// <summary>
/// The prefix for any and all downloaded network resources.
/// </summary>
private static readonly ResPath Prefix = ResPath.Root / "Uploaded";
protected readonly MemoryContentRoot ContentRoot = new();
public virtual void Initialize()
{
_netManager.RegisterNetMessage<NetworkResourceUploadMessage>(ResourceUploadMsg);
// Add our content root to the resource manager.
ResourceManager.AddRoot(Prefix, ContentRoot);
}
protected abstract void ResourceUploadMsg(NetworkResourceUploadMessage msg);
public void Dispose()
{
// This is called automatically when the IoCManager's dependency collection is cleared.
// MemoryContentRoot uses a ReaderWriterLockSlim, which we need to dispose of.
ContentRoot.Dispose();
}
// TODO REPLAYS
// Figure out a way to just directly save NetMessage objects to replays. This just uses IRobustSerializer as a crutch.
[Serializable, NetSerializable]
public sealed class ReplayResourceUploadMsg
{
public byte[] Data = default!;
public ResPath RelativePath = default!;
}
}

View File

@@ -1425,20 +1425,6 @@ namespace Content.Shared.CCVar
* Network Resource Manager * Network Resource Manager
*/ */
/// <summary>
/// Controls whether new resources can be uploaded by admins.
/// Does not prevent already uploaded resources from being sent.
/// </summary>
public static readonly CVarDef<bool> ResourceUploadingEnabled =
CVarDef.Create("netres.enabled", true, CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// Controls the data size limit in megabytes for uploaded resources. If they're too big, they will be dropped.
/// Set to zero or a negative value to disable limit.
/// </summary>
public static readonly CVarDef<float> ResourceUploadingLimitMb =
CVarDef.Create("netres.limit", 3f, CVar.REPLICATED | CVar.SERVER);
/// <summary> /// <summary>
/// Whether uploaded files will be stored in the server's database. /// Whether uploaded files will be stored in the server's database.
/// This is useful to keep "logs" on what files admins have uploaded in the past. /// This is useful to keep "logs" on what files admins have uploaded in the past.

View File

@@ -1,7 +0,0 @@
uploadfolder-command-description = Uploads a folder from your UserData folder recursively to the server contentDB.
uploadfolder-command-help = uploadfolder [folder you want to upload in userdata/UploadFolder]
uploadfolder-command-wrong-args = Wrong number of arguments!
uploadfolder-command-folder-not-found = Folder {$folder} not found!
uploadfolder-command-resource-upload-disabled = Network Resource Uploading is currently disabled. check Server CVars.
uploadfolder-command-file-too-big = File {$filename} above the current size limit! It must be smaller than {$sizeLimit} MB. skipping.
uploadfolder-command-success = Uploaded {$fileCount} files

View File

@@ -124,3 +124,6 @@
- Flags: QUERY - Flags: QUERY
Commands: Commands:
- forall - forall
- uploadfile
- loadprototype
- uploadfolder