mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Remote execute command.
Had to make everything async for this.
This commit is contained in:
@@ -30,3 +30,8 @@ cmd-list-help = Usage: list [filter]
|
||||
cmd-list-heading = SIDE NAME DESC{"\u000A"}-------------------------{"\u000A"}
|
||||
|
||||
cmd-list-arg-filter = [filter]
|
||||
|
||||
## '>' command, aka remote exec
|
||||
cmd-remoteexec-desc = Executes server-side commands
|
||||
cmd-remoteexec-help = Usage: > <command> [arg] [arg] [arg...]
|
||||
Executes a command on the server. This is necessary if a command with the same name exists on the client, as simply running the command would run the client command first.
|
||||
|
||||
@@ -38,10 +38,7 @@ internal sealed partial class ClientConsoleHost
|
||||
if (!RegisteredCommands.TryGetValue(args[0], out var cmd))
|
||||
return Task.FromResult(CompletionResult.Empty);
|
||||
|
||||
if (cmd is ServerDummyCommand)
|
||||
return DoServerCompletions(args, cancel);
|
||||
|
||||
return Task.FromResult(cmd.GetCompletion(LocalShell, args.ToArray()[1..]));
|
||||
return cmd.GetCompletionAsync(LocalShell, args.ToArray()[1..], cancel).AsTask();
|
||||
}
|
||||
|
||||
private Task<CompletionResult> DoServerCompletions(List<string> args, CancellationToken cancel)
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Robust.Client.Log;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
@@ -211,31 +215,61 @@ namespace Robust.Client.Console
|
||||
|
||||
_requestedCommands = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// These dummies are made purely so list and help can list server-side commands.
|
||||
/// </summary>
|
||||
[Reflect(false)]
|
||||
internal sealed class ServerDummyCommand : IConsoleCommand
|
||||
{
|
||||
internal ServerDummyCommand(string command, string help, string description)
|
||||
/// <summary>
|
||||
/// These dummies are made purely so list and help can list server-side commands.
|
||||
/// </summary>
|
||||
[Reflect(false)]
|
||||
private sealed class ServerDummyCommand : IConsoleCommand
|
||||
{
|
||||
Command = command;
|
||||
Help = help;
|
||||
Description = description;
|
||||
internal ServerDummyCommand(string command, string help, string description)
|
||||
{
|
||||
Command = command;
|
||||
Help = help;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
public string Command { get; }
|
||||
|
||||
public string Description { get; }
|
||||
|
||||
public string Help { get; }
|
||||
|
||||
// Always forward to server.
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
shell.RemoteExecuteCommand(argStr);
|
||||
}
|
||||
|
||||
public async ValueTask<CompletionResult> GetCompletionAsync(
|
||||
IConsoleShell shell,
|
||||
string[] args,
|
||||
CancellationToken cancel)
|
||||
{
|
||||
var host = (ClientConsoleHost)shell.ConsoleHost;
|
||||
return await host.DoServerCompletions(args.ToList(), cancel);
|
||||
}
|
||||
}
|
||||
|
||||
public string Command { get; }
|
||||
|
||||
public string Description { get; }
|
||||
|
||||
public string Help { get; }
|
||||
|
||||
// Always forward to server.
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
private sealed class RemoteExecCommand : IConsoleCommand
|
||||
{
|
||||
shell.RemoteExecuteCommand(argStr);
|
||||
public string Command => ">";
|
||||
public string Description => Loc.GetString("cmd-remoteexec-desc");
|
||||
public string Help => Loc.GetString("cmd-remoteexec-help");
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
shell.RemoteExecuteCommand(argStr["> ".Length..]);
|
||||
}
|
||||
|
||||
public async ValueTask<CompletionResult> GetCompletionAsync(
|
||||
IConsoleShell shell,
|
||||
string[] args,
|
||||
CancellationToken cancel)
|
||||
{
|
||||
var host = (ClientConsoleHost)shell.ConsoleHost;
|
||||
return await host.DoServerCompletions(args.ToList(), cancel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -73,7 +74,9 @@ namespace Robust.Server.Console
|
||||
|
||||
// Logger.Debug($"A: {string.Join(", ", args)}");
|
||||
|
||||
#pragma warning disable CA2012
|
||||
return CalcCompletions(sudoShell, args);
|
||||
#pragma warning restore CA2012
|
||||
});
|
||||
|
||||
LoadConsoleCommands();
|
||||
@@ -177,12 +180,12 @@ namespace Robust.Server.Console
|
||||
return session != null ? $"{session.Name}" : "[HOST]";
|
||||
}
|
||||
|
||||
private void HandleConCompletions(MsgConCompletion message)
|
||||
private async void HandleConCompletions(MsgConCompletion message)
|
||||
{
|
||||
var session = _players.GetSessionByChannel(message.MsgChannel);
|
||||
var shell = new ConsoleShell(this, session);
|
||||
|
||||
var result = CalcCompletions(shell, message.Args);
|
||||
var result = await CalcCompletions(shell, message.Args);
|
||||
|
||||
var msg = new MsgConCompletionResp
|
||||
{
|
||||
@@ -190,27 +193,30 @@ namespace Robust.Server.Console
|
||||
Seq = message.Seq
|
||||
};
|
||||
|
||||
if (!message.MsgChannel.IsConnected)
|
||||
return;
|
||||
|
||||
NetManager.ServerSendMessage(msg, message.MsgChannel);
|
||||
}
|
||||
|
||||
private CompletionResult CalcCompletions(IConsoleShell shell, string[] args)
|
||||
private ValueTask<CompletionResult> CalcCompletions(IConsoleShell shell, string[] args)
|
||||
{
|
||||
// Logger.Debug(string.Join(", ", args));
|
||||
|
||||
if (args.Length <= 1)
|
||||
{
|
||||
// Typing out command name, handle this ourselves.
|
||||
return CompletionResult.FromOptions(AvailableCommands.Keys.ToArray());
|
||||
return ValueTask.FromResult(CompletionResult.FromOptions(AvailableCommands.Keys.ToArray()));
|
||||
}
|
||||
|
||||
var cmdName = args[0];
|
||||
if (!AvailableCommands.TryGetValue(cmdName, out var cmd))
|
||||
return CompletionResult.Empty;
|
||||
return ValueTask.FromResult(CompletionResult.Empty);
|
||||
|
||||
if (!ShellCanExecute(shell, cmdName))
|
||||
return CompletionResult.Empty;
|
||||
return ValueTask.FromResult(CompletionResult.Empty);
|
||||
|
||||
return cmd.GetCompletion(shell, args[1..]);
|
||||
return cmd.GetCompletionAsync(shell, args[1..], default);
|
||||
}
|
||||
|
||||
private sealed class SudoShell : IConsoleShell
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.IoC.Exceptions;
|
||||
@@ -63,13 +64,39 @@ namespace Robust.Shared.Console
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterCommand(
|
||||
string command,
|
||||
string description,
|
||||
string help,
|
||||
ConCommandCallback callback)
|
||||
{
|
||||
if (AvailableCommands.ContainsKey(command))
|
||||
throw new InvalidOperationException($"Command already registered: {command}");
|
||||
|
||||
var newCmd = new RegisteredCommand(command, description, help, callback);
|
||||
AvailableCommands.Add(command, newCmd);
|
||||
}
|
||||
|
||||
public void RegisterCommand(
|
||||
string command,
|
||||
string description,
|
||||
string help,
|
||||
ConCommandCallback callback,
|
||||
ConCommandCompletionCallback? completionCallback = null)
|
||||
ConCommandCompletionCallback completionCallback)
|
||||
{
|
||||
if (AvailableCommands.ContainsKey(command))
|
||||
throw new InvalidOperationException($"Command already registered: {command}");
|
||||
|
||||
var newCmd = new RegisteredCommand(command, description, help, callback, completionCallback);
|
||||
AvailableCommands.Add(command, newCmd);
|
||||
}
|
||||
|
||||
public void RegisterCommand(
|
||||
string command,
|
||||
string description,
|
||||
string help,
|
||||
ConCommandCallback callback,
|
||||
ConCommandCompletionAsyncCallback completionCallback)
|
||||
{
|
||||
if (AvailableCommands.ContainsKey(command))
|
||||
throw new InvalidOperationException($"Command already registered: {command}");
|
||||
@@ -163,6 +190,7 @@ namespace Robust.Shared.Console
|
||||
{
|
||||
public ConCommandCallback Callback { get; }
|
||||
public ConCommandCompletionCallback? CompletionCallback { get; }
|
||||
public ConCommandCompletionAsyncCallback? CompletionCallbackAsync { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Command { get; }
|
||||
@@ -185,26 +213,68 @@ namespace Robust.Shared.Console
|
||||
string command,
|
||||
string description,
|
||||
string help,
|
||||
ConCommandCallback callback,
|
||||
ConCommandCompletionCallback? completionCallback = null)
|
||||
ConCommandCallback callback)
|
||||
{
|
||||
Command = command;
|
||||
// Should these two be localized somehow?
|
||||
Description = description;
|
||||
Help = help;
|
||||
Callback = callback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance of <see cref="RegisteredCommand"/>.
|
||||
/// </summary>
|
||||
/// <param name="command">Name of the command.</param>
|
||||
/// <param name="description">Short description of the command.</param>
|
||||
/// <param name="help">Extended description for the command.</param>
|
||||
/// <param name="callback">Callback function that is ran when the command is executed.</param>
|
||||
/// <param name="completionCallback">Callback function to get console completions.</param>
|
||||
public RegisteredCommand(
|
||||
string command,
|
||||
string description,
|
||||
string help,
|
||||
ConCommandCallback callback,
|
||||
ConCommandCompletionCallback completionCallback) : this(command, description, help, callback)
|
||||
{
|
||||
CompletionCallback = completionCallback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance of <see cref="RegisteredCommand"/>.
|
||||
/// </summary>
|
||||
/// <param name="command">Name of the command.</param>
|
||||
/// <param name="description">Short description of the command.</param>
|
||||
/// <param name="help">Extended description for the command.</param>
|
||||
/// <param name="callback">Callback function that is ran when the command is executed.</param>
|
||||
/// <param name="completionCallback">Asynchronous callback function to get console completions.</param>
|
||||
public RegisteredCommand(
|
||||
string command,
|
||||
string description,
|
||||
string help,
|
||||
ConCommandCallback callback,
|
||||
ConCommandCompletionAsyncCallback completionCallback)
|
||||
: this(command, description, help, callback)
|
||||
{
|
||||
CompletionCallbackAsync = completionCallback;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
Callback(shell, argStr, args);
|
||||
}
|
||||
|
||||
public CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
public ValueTask<CompletionResult> GetCompletionAsync(IConsoleShell shell, string[] args)
|
||||
{
|
||||
return CompletionCallback?.Invoke(shell, args) ?? CompletionResult.Empty;
|
||||
if (CompletionCallbackAsync != null)
|
||||
return CompletionCallbackAsync(shell, args);
|
||||
|
||||
if (CompletionCallback != null)
|
||||
return ValueTask.FromResult(CompletionCallback(shell, args));
|
||||
|
||||
return ValueTask.FromResult(CompletionResult.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Robust.Shared.Console
|
||||
@@ -43,5 +44,10 @@ namespace Robust.Shared.Console
|
||||
void Execute(IConsoleShell shell, string argStr, string[] args);
|
||||
|
||||
CompletionResult GetCompletion(IConsoleShell shell, string[] args) => CompletionResult.Empty;
|
||||
|
||||
ValueTask<CompletionResult> GetCompletionAsync(IConsoleShell shell, string[] args, CancellationToken cancel)
|
||||
{
|
||||
return ValueTask.FromResult(GetCompletion(shell, args));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Robust.Shared.Players;
|
||||
|
||||
namespace Robust.Shared.Console
|
||||
@@ -12,6 +13,7 @@ namespace Robust.Shared.Console
|
||||
/// <param name="args">An array of all the parsed arguments.</param>
|
||||
public delegate void ConCommandCallback(IConsoleShell shell, string argStr, string[] args);
|
||||
public delegate CompletionResult ConCommandCompletionCallback(IConsoleShell shell, string[] args);
|
||||
public delegate ValueTask<CompletionResult> ConCommandCompletionAsyncCallback(IConsoleShell shell, string[] args);
|
||||
|
||||
public delegate void ConAnyCommandCallback(IConsoleShell shell, string commandName, string argStr, string[] args);
|
||||
|
||||
@@ -53,6 +55,20 @@ namespace Robust.Shared.Console
|
||||
/// </summary>
|
||||
void LoadConsoleCommands();
|
||||
|
||||
/// <summary>
|
||||
/// Registers a console command into the console system. This is an alternative to
|
||||
/// creating an <see cref="IConsoleCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="command">A string as identifier for this command.</param>
|
||||
/// <param name="description">Short one sentence description of the command.</param>
|
||||
/// <param name="help">Command format string.</param>
|
||||
/// <param name="callback"></param>
|
||||
void RegisterCommand(
|
||||
string command,
|
||||
string description,
|
||||
string help,
|
||||
ConCommandCallback callback);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a console command into the console system. This is an alternative to
|
||||
/// creating an <see cref="IConsoleCommand"/> class.
|
||||
@@ -67,7 +83,23 @@ namespace Robust.Shared.Console
|
||||
string description,
|
||||
string help,
|
||||
ConCommandCallback callback,
|
||||
ConCommandCompletionCallback? completionCallback = null);
|
||||
ConCommandCompletionCallback completionCallback);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a console command into the console system. This is an alternative to
|
||||
/// creating an <see cref="IConsoleCommand"/> class.
|
||||
/// </summary>
|
||||
/// <param name="command">A string as identifier for this command.</param>
|
||||
/// <param name="description">Short one sentence description of the command.</param>
|
||||
/// <param name="help">Command format string.</param>
|
||||
/// <param name="callback"></param>
|
||||
/// <param name="completionCallback"></param>
|
||||
void RegisterCommand(
|
||||
string command,
|
||||
string description,
|
||||
string help,
|
||||
ConCommandCallback callback,
|
||||
ConCommandCompletionAsyncCallback completionCallback);
|
||||
|
||||
/// <summary>
|
||||
/// Unregisters a console command that has been registered previously with <see cref="RegisterCommand(string,string,string,Robust.Shared.Console.ConCommandCallback)"/>.
|
||||
|
||||
Reference in New Issue
Block a user