mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-26 06:27:19 +01:00
Merge branch 'master' of https://github.com/tgstation/tgstation-server-tools into RemoteBranchForTestmerges
This commit is contained in:
@@ -5,8 +5,8 @@ namespace TGCommandLine
|
||||
abstract class ConsoleCommand : Command
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="TGServiceInterface.Interface"/> currently in use by the <see cref="Program"/>
|
||||
/// The <see cref="IInterface"/> currently in use by the <see cref="Program"/>
|
||||
/// </summary>
|
||||
public static Interface Interface;
|
||||
public static IInterface Interface;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace TGCommandLine
|
||||
{
|
||||
abstract class InstanceRootCommand : RootCommand
|
||||
{
|
||||
public static Interface currentInterface;
|
||||
public static IInterface currentInterface;
|
||||
public override ExitCode DoRun(IList<string> parameters)
|
||||
{
|
||||
if (currentInterface.InstanceName == null)
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace TGCommandLine
|
||||
class Program
|
||||
{
|
||||
static bool interactive = false, saidSrvVersion = false;
|
||||
static Interface currentInterface;
|
||||
static IInterface currentInterface;
|
||||
static Command.ExitCode RunCommandLine(IList<string> argsAsList)
|
||||
{
|
||||
//first lookup the connection string
|
||||
@@ -100,7 +100,7 @@ namespace TGCommandLine
|
||||
};
|
||||
}
|
||||
|
||||
static void ReplaceInterface(Interface I)
|
||||
static void ReplaceInterface(IInterface I)
|
||||
{
|
||||
currentInterface = I;
|
||||
ConsoleCommand.Interface = I;
|
||||
@@ -157,7 +157,7 @@ namespace TGCommandLine
|
||||
/// </summary>
|
||||
/// <param name="instanceName">The name of the <see cref="ITGInstance"/> to test</param>
|
||||
/// <param name="silentSuccess">If <see langword="true"/>, does not output on success</param>
|
||||
/// <returns><see langword="true"/> if a <see cref="ConnectivityLevel.Authenticated"/> was achieved with <see cref="Interface.ConnectToInstance(string, bool)"/>, <see langword="false"/> otherwise</returns>
|
||||
/// <returns><see langword="true"/> if a <see cref="ConnectivityLevel.Authenticated"/> was achieved with <see cref="IInterface.ConnectToInstance(string, bool)"/>, <see langword="false"/> otherwise</returns>
|
||||
static bool CheckInstanceConnectivity(string instanceName, bool silentSuccess)
|
||||
{
|
||||
var res = currentInterface.ConnectToInstance(instanceName);
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace TGCommandLine
|
||||
{
|
||||
class CLICommand : RootCommand
|
||||
{
|
||||
public CLICommand(Interface I)
|
||||
public CLICommand(IInterface I)
|
||||
{
|
||||
var tmp = new List<Command> { new UpdateCommand(), new TestmergeCommand(), new RepoCommand(), new BYONDCommand(), new DMCommand(), new DDCommand(), new ConfigCommand(), new IRCCommand(), new DiscordCommand(), new AutoUpdateCommand(), new SetAutoUpdateCommand() };
|
||||
if (I.ConnectToInstance().HasFlag(ConnectivityLevel.Administrator))
|
||||
|
||||
@@ -18,15 +18,15 @@ namespace TGControlPanel
|
||||
public static IDictionary<string, ControlPanel> InstancesInUse { get; private set; } = new Dictionary<string, ControlPanel>();
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="TGServiceInterface.Interface"/> instance for this <see cref="ControlPanel"/>
|
||||
/// The <see cref="IInterface"/> instance for this <see cref="ControlPanel"/>
|
||||
/// </summary>
|
||||
readonly Interface Interface;
|
||||
readonly IInterface Interface;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a <see cref="ControlPanel"/>
|
||||
/// </summary>
|
||||
/// <param name="I">The <see cref="TGServiceInterface.Interface"/> for the <see cref="ControlPanel"/></param>
|
||||
public ControlPanel(Interface I)
|
||||
/// <param name="I">The <see cref="IInterface"/> for the <see cref="ControlPanel"/></param>
|
||||
public ControlPanel(IInterface I)
|
||||
{
|
||||
InitializeComponent();
|
||||
Interface = I;
|
||||
|
||||
@@ -12,14 +12,14 @@ namespace TGControlPanel
|
||||
partial class InstanceSelector : CountedForm
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="Interface"/> we build instance connections from
|
||||
/// The <see cref="IInterface"/> we build instance connections from
|
||||
/// </summary>
|
||||
readonly Interface masterInterface;
|
||||
readonly IInterface masterInterface;
|
||||
/// <summary>
|
||||
/// List of <see cref="InstanceMetadata"/> from <see cref="masterInterface"/>
|
||||
/// </summary>
|
||||
IList<InstanceMetadata> InstanceData;
|
||||
public InstanceSelector(Interface I)
|
||||
public InstanceSelector(IInterface I)
|
||||
{
|
||||
InitializeComponent();
|
||||
InstanceListBox.MouseDoubleClick += InstanceListBox_MouseDoubleClick;
|
||||
@@ -100,7 +100,7 @@ namespace TGControlPanel
|
||||
activeCP.BringToFront();
|
||||
return;
|
||||
}
|
||||
var InstanceAccessor = new Interface(masterInterface);
|
||||
var InstanceAccessor = new Interface(masterInterface as Interface);
|
||||
try
|
||||
{
|
||||
ConnectivityLevel res = ConnectivityLevel.None;
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace TGControlPanel
|
||||
VerifyAndConnect(new Interface());
|
||||
}
|
||||
|
||||
void VerifyAndConnect(Interface I)
|
||||
void VerifyAndConnect(IInterface I)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace TGInstallerWrapper
|
||||
bool cancelled = false;
|
||||
bool pathIsDefault = true;
|
||||
|
||||
Interface Interface;
|
||||
IInterface Interface;
|
||||
|
||||
/// <summary>
|
||||
/// Construct an installer form
|
||||
|
||||
@@ -530,7 +530,7 @@ namespace TGServerService
|
||||
return;
|
||||
//Copy the interface dll to the static dir
|
||||
|
||||
var InterfacePath = Assembly.GetAssembly(typeof(Interface)).Location;
|
||||
var InterfacePath = Assembly.GetAssembly(typeof(IInterface)).Location;
|
||||
//bridge is installed next to the interface
|
||||
var BridgePath = Path.Combine(Path.GetDirectoryName(InterfacePath), BridgeDLLName);
|
||||
#if DEBUG
|
||||
|
||||
@@ -214,8 +214,6 @@ namespace TGServerService
|
||||
{
|
||||
var newVersion = Config.SettingsVersion;
|
||||
Config.Upgrade();
|
||||
|
||||
PrePrepConfig();
|
||||
|
||||
for (var oldVersion = Config.SettingsVersion; oldVersion < newVersion; ++oldVersion)
|
||||
MigrateSettings(oldVersion);
|
||||
@@ -225,6 +223,8 @@ namespace TGServerService
|
||||
Config.UpgradeRequired = false;
|
||||
Config.Save();
|
||||
}
|
||||
|
||||
PrePrepConfig();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -12,9 +12,74 @@ using TGServiceInterface.Components;
|
||||
namespace TGServiceInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// Main inteface class for the service
|
||||
/// Main <see langword="interface"/> for communicating the <see cref="ITGSService"/>
|
||||
/// </summary>
|
||||
sealed public class Interface : IDisposable
|
||||
public interface IInterface : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the current instance in use. Defaults to <see langword="null"/>
|
||||
/// </summary>
|
||||
string InstanceName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If this is set, we will try and connect to an HTTPS server running at this address
|
||||
/// </summary>
|
||||
string HTTPSURL { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The port used to connect to the <see cref="ITGSService"/>
|
||||
/// </summary>
|
||||
ushort HTTPSPort { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the <see cref="IInterface"/> is setup for a remote connection
|
||||
/// </summary>
|
||||
bool IsRemoteConnection { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Targets <paramref name="instanceName"/> as the instance to use with <see cref="GetComponent{T}"/>. Closes all connections to any previous instance
|
||||
/// </summary>
|
||||
/// <param name="instanceName">The name of the instance to connect to</param>
|
||||
/// <param name="skipChecks">If set to <see langword="true"/>, skips the connectivity and authentication checks, sets <see cref="InstanceName"/>, and returns <see cref="ConnectivityLevel.Connected"/></param>
|
||||
/// <returns>The apporopriate <see cref="ConnectivityLevel"/></returns>
|
||||
ConnectivityLevel ConnectToInstance(string instanceName = null, bool skipChecks = false);
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true"/> if the <see cref="IInterface"/> interface being used to connect to a service does not have the same release version as the service
|
||||
/// </summary>
|
||||
/// <param name="errorMessage">An error message to display to the user should this function return <see langword="true"/></param>
|
||||
/// <returns><see langword="true"/> if the <see cref="IInterface"/> interface being used to connect to a service does not have the same release version as the service</returns>
|
||||
bool VersionMismatch(out string errorMessage);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the requested <see cref="IInterface"/> component <see langword="interface"/> for the instance <see cref="InstanceName"/>. This does not guarantee a successful connection. <see cref="ChannelFactory{TChannel}"/>s created this way are recycled for minimum latency and bandwidth usage
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The component <see langword="interface"/> to retrieve</typeparam>
|
||||
/// <returns>The correct component <see langword="interface"/></returns>
|
||||
T GetComponent<T>();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="ITGSService"/> component for the service
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="ITGSService"/> component for the service</returns>
|
||||
ITGSService GetService();
|
||||
|
||||
/// <summary>
|
||||
/// Used to test if the <see cref="ITGSService"/> is avaiable on the target machine. Note that state can change at any time and any call into the may throw an exception because of communcation errors
|
||||
/// </summary>
|
||||
/// <returns><see langword="null"/> on successful connection, error message <see cref="string"/> on failure</returns>
|
||||
ConnectivityLevel ConnectionStatus();
|
||||
|
||||
/// <summary>
|
||||
/// Used to test if the <see cref="ITGSService"/> is avaiable on the target machine. Note that state can change at any time and any call into the may throw an exception because of communcation errors
|
||||
/// </summary>
|
||||
/// <param name="error">String of the error that prevented an elevated connectivity level</param>
|
||||
/// <returns>The apporopriate <see cref="ConnectivityLevel"/></returns>
|
||||
ConnectivityLevel ConnectionStatus(out string error);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
sealed public class Interface : IInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// List of <see langword="interface"/>s that can be used with <see cref="GetComponent{T}"/> and <see cref="CreateChannel{T}"/>
|
||||
@@ -40,21 +105,24 @@ namespace TGServiceInterface
|
||||
/// </summary>
|
||||
public const string InstanceInterfaceName = MasterInterfaceName + "/Instance";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The name of the current instance in use. Defaults to <see langword="null"/>
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public string InstanceName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// If this is set, we will try and connect to an HTTPS server running at this address
|
||||
/// </summary>
|
||||
public readonly string HTTPSURL;
|
||||
readonly string _HTTPSURL;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string HTTPSURL { get { return _HTTPSURL; } }
|
||||
|
||||
/// <summary>
|
||||
/// The port used by the service
|
||||
/// The port used to connect to the <see cref="ITGSService"/>
|
||||
/// </summary>
|
||||
public readonly ushort HTTPSPort;
|
||||
readonly ushort _HTTPSPort;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ushort HTTPSPort { get { return _HTTPSPort; } }
|
||||
|
||||
/// <summary>
|
||||
/// Username for remote operations
|
||||
@@ -133,8 +201,8 @@ namespace TGServiceInterface
|
||||
/// <param name="password">Windows account password for the remote server</param>
|
||||
public Interface(string address, ushort port, string username, string password)
|
||||
{
|
||||
HTTPSURL = address;
|
||||
HTTPSPort = port;
|
||||
_HTTPSURL = address;
|
||||
_HTTPSPort = port;
|
||||
HTTPSUsername = username;
|
||||
HTTPSPassword = password;
|
||||
}
|
||||
@@ -142,15 +210,10 @@ namespace TGServiceInterface
|
||||
/// <summary>
|
||||
/// Constructs an <see cref="Interface"/> that connects to the same <see cref="ITGSService"/> as some <paramref name="other"/> <see cref="ITGInstance"/>
|
||||
/// </summary>
|
||||
/// <param name="other"></param>
|
||||
/// <param name="other">Another <see cref="Interface"/> to copy settings from</param>
|
||||
public Interface(Interface other) : this(other.HTTPSURL, other.HTTPSPort, other.HTTPSUsername, other.HTTPSPassword) { }
|
||||
|
||||
/// <summary>
|
||||
/// Targets <paramref name="instanceName"/> as the instance to use with <see cref="GetComponent{T}"/>. Closes all connections to any previous instance
|
||||
/// </summary>
|
||||
/// <param name="instanceName">The name of the instance to connect to</param>
|
||||
/// <param name="skipChecks">If set to <see langword="true"/>, skips the connectivity and authentication checks, sets <see cref="InstanceName"/>, and returns <see cref="ConnectivityLevel.Connected"/></param>
|
||||
/// <returns>The apporopriate <see cref="ConnectivityLevel"/></returns>
|
||||
/// <inheritdoc />
|
||||
public ConnectivityLevel ConnectToInstance(string instanceName = null, bool skipChecks = false)
|
||||
{
|
||||
if (instanceName == null)
|
||||
@@ -191,9 +254,7 @@ namespace TGServiceInterface
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the <see cref="Interface"/> is setup for a remote connection
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public bool IsRemoteConnection { get { return HTTPSURL != null; } }
|
||||
|
||||
/// <summary>
|
||||
@@ -224,11 +285,7 @@ namespace TGServiceInterface
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true"/> if the <see cref="Interface"/> interface being used to connect to a service does not have the same release version as the service
|
||||
/// </summary>
|
||||
/// <param name="errorMessage">An error message to display to the user should this function return <see langword="true"/></param>
|
||||
/// <returns><see langword="true"/> if the <see cref="Interface"/> interface being used to connect to a service does not have the same release version as the service</returns>
|
||||
/// <inheritdoc />
|
||||
public bool VersionMismatch(out string errorMessage)
|
||||
{
|
||||
var splits = GetService().Version().Split(' ');
|
||||
@@ -253,11 +310,7 @@ namespace TGServiceInterface
|
||||
(sender as IDisposable).Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the requested <see cref="Interface"/> component <see langword="interface"/> for the instance <see cref="InstanceName"/>. This does not guarantee a successful connection. <see cref="ChannelFactory{TChannel}"/>s created this way are recycled for minimum latency and bandwidth usage
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The component <see langword="interface"/> to retrieve</typeparam>
|
||||
/// <returns>The correct component <see langword="interface"/></returns>
|
||||
/// <inheritdoc />
|
||||
public T GetComponent<T>()
|
||||
{
|
||||
var ToT = typeof(T);
|
||||
@@ -265,7 +318,13 @@ namespace TGServiceInterface
|
||||
throw new Exception("Invalid type!");
|
||||
return GetComponentImpl<T>(true);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the requested <see cref="Interface"/> component <see langword="interface"/> for the instance <see cref="InstanceName"/>. This does not guarantee a successful connection. <see cref="ChannelFactory{TChannel}"/>s created this way are recycled for minimum latency and bandwidth usage
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The component <see langword="interface"/> to retrieve</typeparam>
|
||||
/// <param name="useInstanceName">If <see cref="InstanceName"/> should be used to connect</param>
|
||||
/// <returns>The correct component <see langword="interface"/></returns>
|
||||
T GetComponentImpl<T>(bool useInstanceName)
|
||||
{
|
||||
if (useInstanceName & InstanceName == null)
|
||||
@@ -297,10 +356,7 @@ namespace TGServiceInterface
|
||||
return cf.CreateChannel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="ITGSService"/> component for the service
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="ITGSService"/> component for the service</returns>
|
||||
/// <inheritdoc />
|
||||
public ITGSService GetService()
|
||||
{
|
||||
return GetComponentImpl<ITGSService>(false);
|
||||
@@ -341,24 +397,18 @@ namespace TGServiceInterface
|
||||
{
|
||||
res.Credentials.UserName.UserName = HTTPSUsername;
|
||||
res.Credentials.UserName.Password = HTTPSPassword;
|
||||
res.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to test if the <see cref="ITGSService"/> is avaiable on the target machine. Note that state can change at any time and any call into the may throw an exception because of communcation errors
|
||||
/// </summary>
|
||||
/// <returns><see langword="null"/> on successful connection, error message <see cref="string"/> on failure</returns>
|
||||
/// <inheritdoc />
|
||||
public ConnectivityLevel ConnectionStatus()
|
||||
{
|
||||
return ConnectionStatus(out string unused);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to test if the <see cref="ITGSService"/> is avaiable on the target machine. Note that state can change at any time and any call into the may throw an exception because of communcation errors
|
||||
/// </summary>
|
||||
/// <param name="error">String of the error that prevented an elevated connectivity level</param>
|
||||
/// <returns>The apporopriate <see cref="ConnectivityLevel"/></returns>
|
||||
/// <inheritdoc />
|
||||
public ConnectivityLevel ConnectionStatus(out string error)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.ServiceModel;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using TGServiceInterface.Components;
|
||||
|
||||
namespace TGServiceInterface.Tests
|
||||
{
|
||||
@@ -10,6 +12,10 @@ namespace TGServiceInterface.Tests
|
||||
[TestClass]
|
||||
public class TestInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// Name to use for testing <see cref="ITGInstance"/>s
|
||||
/// </summary>
|
||||
const string TestInstanceName = "TestInstance";
|
||||
/// <summary>
|
||||
/// Test that <see cref="Interface.SetBadCertificateHandler(Func{string, bool})"/> can execute successfully
|
||||
/// </summary>
|
||||
@@ -76,5 +82,14 @@ namespace TGServiceInterface.Tests
|
||||
Assert.AreEqual(first.HTTPSPort, second.HTTPSPort);
|
||||
Assert.IsTrue(second.IsRemoteConnection);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestRemoteAccessInterfaceAllowsWindowsImpersonation()
|
||||
{
|
||||
var inter = CreateFakeRemoteInterface();
|
||||
var po = new PrivateObject(inter);
|
||||
var cf = (ChannelFactory<ITGConfig>)po.Invoke("CreateChannel", new Type[] { typeof(string) }, new object[] { TestInstanceName }, new Type[] { typeof(ITGConfig) });
|
||||
Assert.AreEqual(cf.Credentials.Windows.AllowedImpersonationLevel, System.Security.Principal.TokenImpersonationLevel.Impersonation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,9 @@ namespace TGServerService.Tests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test <see cref="Service.OnStart(string[])"/> and <see cref="Service.OnStop"/> can execute successfully
|
||||
/// Starts and stops a <see cref="Service"/>
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public void TestStartupAndShutdown()
|
||||
void StartStopServiceBasic()
|
||||
{
|
||||
using (var S = new ServiceAccessor())
|
||||
{
|
||||
@@ -30,6 +29,15 @@ namespace TGServerService.Tests
|
||||
S.FakeStop();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test <see cref="Service.OnStart(string[])"/> and <see cref="Service.OnStop"/> can execute successfully
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public void TestStartupAndShutdown()
|
||||
{
|
||||
StartStopServiceBasic();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test <see cref="Service.OnStart(string[])"/> and <see cref="Service.OnStop"/> can execute successfully with a commandline port override
|
||||
@@ -37,11 +45,29 @@ namespace TGServerService.Tests
|
||||
[TestMethod]
|
||||
public void TestCommandLinePortSet()
|
||||
{
|
||||
Properties.Settings.Default.RemoteAccessPort = 11111;
|
||||
using (var S = new ServiceAccessor())
|
||||
{
|
||||
S.FakeStart(new string[] { "-port", "36785" });
|
||||
S.FakeStop();
|
||||
}
|
||||
Assert.AreEqual(Properties.Settings.Default.RemoteAccessPort, 36785);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test that the .NET config is always initialized regardless of <see cref="Properties.Settings.UpgradeRequired"/>
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public void TestNETConfigIsAlwaysPrepped()
|
||||
{
|
||||
Properties.Settings.Default.UpgradeRequired = true;
|
||||
Properties.Settings.Default.InstancePaths = null;
|
||||
StartStopServiceBasic();
|
||||
Assert.IsNotNull(Properties.Settings.Default.InstancePaths);
|
||||
Properties.Settings.Default.UpgradeRequired = false;
|
||||
Properties.Settings.Default.InstancePaths = null;
|
||||
StartStopServiceBasic();
|
||||
Assert.IsNotNull(Properties.Settings.Default.InstancePaths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user