Merge pull request #330 from Cyberboss/Permissions

Fixes required for 3.2
This commit is contained in:
Jordan Brown
2017-11-10 14:11:23 -05:00
committed by GitHub
22 changed files with 323 additions and 183 deletions
+1 -1
View File
@@ -85,7 +85,7 @@ namespace TGCommandLine
}
else if (interactive && !saidSrvVersion)
{
Console.WriteLine("Connectd to service version: " + currentInterface.GetService().Version());
Console.WriteLine("Connectd to service version: " + currentInterface.GetServiceComponent<ITGLanding>().Version());
saidSrvVersion = true;
}
+22 -21
View File
@@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
using TGServiceInterface;
using TGServiceInterface.Components;
namespace TGCommandLine
{
/// <summary>
/// Used for managing the <see cref="TGServiceInterface.Components.ITGSService"/>
/// Used for managing the <see cref="ITGSService"/> components
/// </summary>
class ServiceCommand : RootCommand
{
@@ -26,7 +27,7 @@ namespace TGCommandLine
}
/// <summary>
/// Command for calling <see cref="TGServiceInterface.Components.ITGSService.CreateInstance(string, string)"/>
/// Command for calling <see cref="ITGInstanceManager.CreateInstance(string, string)"/>
/// </summary>
class ServiceCreateInstanceCommand : ConsoleCommand
{
@@ -54,7 +55,7 @@ namespace TGCommandLine
/// <inheritdoc />
protected override ExitCode Run(IList<string> parameters)
{
var res = Interface.GetService().CreateInstance(parameters[0], parameters[1]);
var res = Interface.GetServiceComponent<ITGInstanceManager>().CreateInstance(parameters[0], parameters[1]);
if (res != null)
{
OutputProc(res);
@@ -65,7 +66,7 @@ namespace TGCommandLine
}
/// <summary>
/// Command for calling <see cref="TGServiceInterface.Components.ITGSService.ListInstances"/>
/// Command for calling <see cref="ITGLanding.ListInstances"/>
/// </summary>
class ServiceListInstancesCommand : ConsoleCommand
{
@@ -86,14 +87,14 @@ namespace TGCommandLine
/// <inheritdoc />
protected override ExitCode Run(IList<string> parameters)
{
foreach (var I in Interface.GetService().ListInstances())
foreach (var I in Interface.GetServiceComponent<ITGLanding>().ListInstances())
OutputProc(String.Format("{0} ({1}):\t{2}{3}", I.Name, I.Path, I.Enabled ? "Online" : "Offline", I.Enabled ? String.Format(" ({0})", I.LoggingID) : ""));
return ExitCode.Normal;
}
}
/// <summary>
/// Command for calling <see cref="TGServiceInterface.Components.ITGSService.DetachInstance(string)"/>
/// Command for calling <see cref="ITGInstanceManager.DetachInstance(string)"/>
/// </summary>
class ServiceDetachInstanceCommand : ConsoleCommand
{
@@ -121,7 +122,7 @@ namespace TGCommandLine
/// <inheritdoc />
protected override ExitCode Run(IList<string> parameters)
{
var res = Interface.GetService().DetachInstance(parameters[0]);
var res = Interface.GetServiceComponent<ITGInstanceManager>().DetachInstance(parameters[0]);
if (res != null)
{
OutputProc(res);
@@ -132,7 +133,7 @@ namespace TGCommandLine
}
/// <summary>
/// Command for calling <see cref="TGServiceInterface.Components.ITGSService.ImportInstance(string)"/>
/// Command for calling <see cref="ITGInstanceManager.ImportInstance(string)"/>
/// </summary>
class ServiceImportInstanceCommand : ConsoleCommand
{
@@ -160,7 +161,7 @@ namespace TGCommandLine
/// <inheritdoc />
protected override ExitCode Run(IList<string> parameters)
{
var res = Interface.GetService().ImportInstance(parameters[0]);
var res = Interface.GetServiceComponent<ITGInstanceManager>().ImportInstance(parameters[0]);
if (res != null)
{
OutputProc(res);
@@ -171,7 +172,7 @@ namespace TGCommandLine
}
/// <summary>
/// Command for calling <see cref="TGServiceInterface.Components.ITGSService.PythonPath"/>
/// Command for calling <see cref="ITGSService.PythonPath"/>
/// </summary>
class ServicePythonPathCommand : ConsoleCommand
{
@@ -192,7 +193,7 @@ namespace TGCommandLine
/// <inheritdoc />
protected override ExitCode Run(IList<string> parameters)
{
var res = Interface.GetService().PythonPath();
var res = Interface.GetServiceComponent<ITGSService>().PythonPath();
if (res != null)
{
OutputProc(res);
@@ -203,7 +204,7 @@ namespace TGCommandLine
}
/// <summary>
/// Command for calling <see cref="TGServiceInterface.Components.ITGSService.SetPythonPath(string)"/>
/// Command for calling <see cref="ITGSService.SetPythonPath(string)"/>
/// </summary>
class ServiceSetPythonPathCommand : ConsoleCommand
{
@@ -231,13 +232,13 @@ namespace TGCommandLine
/// <inheritdoc />
protected override ExitCode Run(IList<string> parameters)
{
Interface.GetService().SetPythonPath(parameters[0]);
Interface.GetServiceComponent<ITGSService>().SetPythonPath(parameters[0]);
return ExitCode.Normal;
}
}
/// <summary>
/// Command for calling <see cref="TGServiceInterface.Components.ITGSService.SetInstanceEnabled(string, bool)"/> with a <see langword="true"/> parameter
/// Command for calling <see cref="ITGInstanceManager.SetInstanceEnabled(string, bool)"/> with a <see langword="true"/> parameter
/// </summary>
class ServiceEnableInstanceCommand : ConsoleCommand
{
@@ -265,7 +266,7 @@ namespace TGCommandLine
/// <inheritdoc />
protected override ExitCode Run(IList<string> parameters)
{
var res = Interface.GetService().SetInstanceEnabled(parameters[0], true);
var res = Interface.GetServiceComponent<ITGInstanceManager>().SetInstanceEnabled(parameters[0], true);
if (res != null)
{
OutputProc(res);
@@ -276,7 +277,7 @@ namespace TGCommandLine
}
/// <summary>
/// Command for calling <see cref="TGServiceInterface.Components.ITGSService.SetInstanceEnabled(string, bool)"/> with a <see langword="false"/> parameter
/// Command for calling <see cref="ITGInstanceManager.SetInstanceEnabled(string, bool)"/> with a <see langword="false"/> parameter
/// </summary>
class ServiceDisableInstanceCommand : ConsoleCommand
{
@@ -304,7 +305,7 @@ namespace TGCommandLine
/// <inheritdoc />
protected override ExitCode Run(IList<string> parameters)
{
var res = Interface.GetService().SetInstanceEnabled(parameters[0], false);
var res = Interface.GetServiceComponent<ITGInstanceManager>().SetInstanceEnabled(parameters[0], false);
if (res != null)
{
OutputProc(res);
@@ -336,7 +337,7 @@ namespace TGCommandLine
/// <inheritdoc />
protected override ExitCode Run(IList<string> parameters)
{
OutputProc(Interface.GetService().RemoteAccessPort().ToString());
OutputProc(Interface.GetServiceComponent<ITGSService>().RemoteAccessPort().ToString());
return ExitCode.Normal;
}
}
@@ -381,7 +382,7 @@ namespace TGCommandLine
return ExitCode.BadCommand;
}
var res = Interface.GetService().SetRemoteAccessPort(port);
var res = Interface.GetServiceComponent<ITGSService>().SetRemoteAccessPort(port);
if (res != null)
{
OutputProc(res);
@@ -393,7 +394,7 @@ namespace TGCommandLine
}
/// <summary>
/// Command for calling <see cref="TGServiceInterface.Components.ITGSService.RenameInstance(string, string)"/>
/// Command for calling <see cref="ITGInstanceManager.RenameInstance(string, string)"/>
/// </summary>
class ServiceRenameInstanceCommand : ConsoleCommand
{
@@ -421,7 +422,7 @@ namespace TGCommandLine
/// <inheritdoc />
protected override ExitCode Run(IList<string> parameters)
{
var res = Interface.GetService().RenameInstance(parameters[0], parameters[1]);
var res = Interface.GetServiceComponent<ITGInstanceManager>().RenameInstance(parameters[0], parameters[1]);
if (res != null)
{
OutputProc(res);
+1 -1
View File
@@ -10,7 +10,7 @@ namespace TGControlPanel
/// <summary>
/// The main <see cref="ControlPanel"/> form
/// </summary>
partial class ControlPanel : CountedForm
sealed partial class ControlPanel : CountedForm
{
/// <summary>
/// List of instances being used by open control panels
+1 -1
View File
@@ -5,7 +5,7 @@ namespace TGControlPanel
/// <summary>
/// Calls <see cref="Application.Exit()"/> when all <see cref="CountedForm"/>s are <see cref="Form.Close"/>d
/// </summary>
class CountedForm : Form
abstract class CountedForm : Form
{
/// <summary>
/// The current number of active <see cref="CountedForm"/>s
+32 -1
View File
@@ -36,6 +36,8 @@
this.RenameInstanceButton = new System.Windows.Forms.Button();
this.DetachInstanceButton = new System.Windows.Forms.Button();
this.RefreshButton = new System.Windows.Forms.Button();
this.ConnectButton = new System.Windows.Forms.Button();
this.EnabledCheckBox = new System.Windows.Forms.CheckBox();
this.SuspendLayout();
//
// InstanceListBox
@@ -46,6 +48,7 @@
this.InstanceListBox.Name = "InstanceListBox";
this.InstanceListBox.Size = new System.Drawing.Size(339, 238);
this.InstanceListBox.TabIndex = 0;
this.InstanceListBox.SelectedIndexChanged += new System.EventHandler(this.InstanceListBox_SelectedIndexChanged);
//
// CreateInstanceButton
//
@@ -94,7 +97,7 @@
// RefreshButton
//
this.RefreshButton.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.RefreshButton.Location = new System.Drawing.Point(358, 226);
this.RefreshButton.Location = new System.Drawing.Point(358, 195);
this.RefreshButton.Name = "RefreshButton";
this.RefreshButton.Size = new System.Drawing.Size(148, 25);
this.RefreshButton.TabIndex = 19;
@@ -102,12 +105,37 @@
this.RefreshButton.UseVisualStyleBackColor = true;
this.RefreshButton.Click += new System.EventHandler(this.RefreshButton_Click);
//
// ConnectButton
//
this.ConnectButton.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.ConnectButton.Location = new System.Drawing.Point(358, 226);
this.ConnectButton.Name = "ConnectButton";
this.ConnectButton.Size = new System.Drawing.Size(148, 25);
this.ConnectButton.TabIndex = 20;
this.ConnectButton.Text = "Connect";
this.ConnectButton.UseVisualStyleBackColor = true;
this.ConnectButton.Click += new System.EventHandler(this.ConnectButton_Click);
//
// EnabledCheckBox
//
this.EnabledCheckBox.AutoSize = true;
this.EnabledCheckBox.ForeColor = System.Drawing.Color.White;
this.EnabledCheckBox.Location = new System.Drawing.Point(396, 149);
this.EnabledCheckBox.Name = "EnabledCheckBox";
this.EnabledCheckBox.Size = new System.Drawing.Size(65, 17);
this.EnabledCheckBox.TabIndex = 21;
this.EnabledCheckBox.Text = "Enabled";
this.EnabledCheckBox.UseVisualStyleBackColor = true;
this.EnabledCheckBox.CheckedChanged += new System.EventHandler(this.EnabledCheckBox_CheckedChanged);
//
// InstanceSelector
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(39)))), ((int)(((byte)(40)))), ((int)(((byte)(34)))));
this.ClientSize = new System.Drawing.Size(518, 261);
this.Controls.Add(this.EnabledCheckBox);
this.Controls.Add(this.ConnectButton);
this.Controls.Add(this.RefreshButton);
this.Controls.Add(this.DetachInstanceButton);
this.Controls.Add(this.RenameInstanceButton);
@@ -119,6 +147,7 @@
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Server Instances";
this.ResumeLayout(false);
this.PerformLayout();
}
@@ -130,5 +159,7 @@
private System.Windows.Forms.Button RenameInstanceButton;
private System.Windows.Forms.Button DetachInstanceButton;
private System.Windows.Forms.Button RefreshButton;
private System.Windows.Forms.Button ConnectButton;
private System.Windows.Forms.CheckBox EnabledCheckBox;
}
}
+91 -20
View File
@@ -3,13 +3,14 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Forms;
using TGServiceInterface;
using TGServiceInterface.Components;
namespace TGControlPanel
{
/// <summary>
/// Form used for managing <see cref="TGServiceInterface.Components.ITGSService"/> <see cref="TGServiceInterface.Components.ITGInstance"/> manipulation functions
/// Form used for managing <see cref="ITGSService"/> <see cref="ITGInstance"/> manipulation functions
/// </summary>
partial class InstanceSelector : CountedForm
sealed partial class InstanceSelector : CountedForm
{
/// <summary>
/// The <see cref="IInterface"/> we build instance connections from
@@ -19,6 +20,15 @@ namespace TGControlPanel
/// List of <see cref="InstanceMetadata"/> from <see cref="masterInterface"/>
/// </summary>
IList<InstanceMetadata> InstanceData;
/// <summary>
/// Used for modifying <see cref="EnabledCheckBox"/> without invoking its side effects
/// </summary>
bool UpdatingEnabledCheckbox = false;
/// <summary>
/// Construct an <see cref="InstanceSelector"/>
/// </summary>
/// <param name="I">An <see cref="IInterface"/> connected a the <see cref="ITGSService"/></param>
public InstanceSelector(IInterface I)
{
InitializeComponent();
@@ -47,15 +57,13 @@ namespace TGControlPanel
}
/// <summary>
/// Connects to a <see cref="TGServiceInterface.Components.ITGInstance"/> if it is double clicked in <see cref="InstanceListBox"/>
/// Connects to a <see cref="ITGInstance"/> if it is double clicked in <see cref="InstanceListBox"/>
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="MouseEventArgs"/></param>
void InstanceListBox_MouseDoubleClick(object sender, MouseEventArgs e)
{
var index = InstanceListBox.IndexFromPoint(e.Location);
if (index != ListBox.NoMatches)
TryConnectToInstance(InstanceData[index].Name);
TryConnectToIndexInstance(InstanceListBox.IndexFromPoint(e.Location));
}
/// <summary>
@@ -77,25 +85,36 @@ namespace TGControlPanel
}
/// <summary>
/// Loads the <see cref="InstanceListBox"/> using <see cref="TGServiceInterface.Components.ITGSService.ListInstances"/>
/// Loads the <see cref="InstanceListBox"/> using <see cref="ITGLanding.ListInstances"/>
/// </summary>
async void RefreshInstances()
{
InstanceListBox.Items.Clear();
await WrapServerOp(() => {
InstanceData = masterInterface.GetService().ListInstances();
InstanceData = masterInterface.GetServiceComponent<ITGLanding>().ListInstances();
});
foreach(var I in InstanceData)
InstanceListBox.Items.Add(String.Format("{0}: {1} - {2} - {3}", I.LoggingID, I.Name, I.Path, I.Enabled ? "ONLINE" : "OFFLINE"));
var HasServerAdmin = masterInterface.ConnectionStatus().HasFlag(ConnectivityLevel.Administrator);
CreateInstanceButton.Enabled = HasServerAdmin;
ImportInstanceButton.Enabled = HasServerAdmin;
RenameInstanceButton.Enabled = HasServerAdmin;
DetachInstanceButton.Enabled = HasServerAdmin;
EnabledCheckBox.Enabled = HasServerAdmin;
if(InstanceData.Count > 0)
InstanceListBox.SelectedIndex = 0;
}
/// <summary>
/// Tries to start a <see cref="ControlPanel"/> for a given <paramref name="instanceName"/>
/// Tries to start a <see cref="ControlPanel"/> for a given <see cref="InstanceListBox"/> <paramref name="index"/>
/// </summary>
/// <param name="instanceName">The name of the <see cref="TGServiceInterface.Components.ITGInstance"/> to connect to</param>
async void TryConnectToInstance(string instanceName)
/// <param name="index">The <see cref="ListBox.SelectedIndex"/> of <see cref="InstanceListBox"/> to connect to</param>
async void TryConnectToIndexInstance(int index)
{
if(ControlPanel.InstancesInUse.TryGetValue(instanceName, out ControlPanel activeCP))
if (index == ListBox.NoMatches)
return;
var instanceName = InstanceData[index].Name;
if (ControlPanel.InstancesInUse.TryGetValue(instanceName, out ControlPanel activeCP))
{
activeCP.BringToFront();
return;
@@ -123,7 +142,7 @@ namespace TGControlPanel
}
/// <summary>
/// Prompts the user for parameters to <see cref="TGServiceInterface.Components.ITGSService.DetachInstance(string)"/>
/// Prompts the user for parameters to <see cref="ITGInstanceManager.DetachInstance(string)"/>
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="EventArgs"/></param>
@@ -135,7 +154,7 @@ namespace TGControlPanel
if (MessageBox.Show(String.Format("This will dissociate the server instance at \"{0}\"! Are you sure?", imd.Path), "Instance Detach", MessageBoxButtons.YesNo) != DialogResult.Yes)
return;
string res = null;
await WrapServerOp(() => { res = masterInterface.GetService().DetachInstance(imd.Name); });
await WrapServerOp(() => res = masterInterface.GetServiceComponent<ITGInstanceManager>().DetachInstance(imd.Name));
if (res != null)
MessageBox.Show(res);
RefreshInstances();
@@ -152,7 +171,7 @@ namespace TGControlPanel
}
/// <summary>
/// Prompts the user for parameters to <see cref="TGServiceInterface.Components.ITGSService.RenameInstance(string, string)"/>
/// Prompts the user for parameters to <see cref="ITGInstanceManager.RenameInstance(string, string)"/>
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="EventArgs"/></param>
@@ -167,14 +186,14 @@ namespace TGControlPanel
if (imd.Enabled && MessageBox.Show(String.Format("This will temporarily offline the server instance! Are you sure?", imd.Path), "Instance Restart", MessageBoxButtons.YesNo) != DialogResult.Yes)
return;
string res = null;
await WrapServerOp(() => { res = masterInterface.GetService().RenameInstance(imd.Name, new_name); });
await WrapServerOp(() => res = masterInterface.GetServiceComponent<ITGInstanceManager>().RenameInstance(imd.Name, new_name));
if (res != null)
MessageBox.Show(res);
RefreshInstances();
}
/// <summary>
/// Prompts the user for parameters to <see cref="TGServiceInterface.Components.ITGSService.ImportInstance(string)"/>
/// Prompts the user for parameters to <see cref="ITGInstanceManager.ImportInstance(string)"/>
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="EventArgs"/></param>
@@ -184,14 +203,14 @@ namespace TGControlPanel
if (instance_path == null)
return;
string res = null;
await WrapServerOp(() => { res = masterInterface.GetService().ImportInstance(instance_path); });
await WrapServerOp(() => res = masterInterface.GetServiceComponent<ITGInstanceManager>().ImportInstance(instance_path));
if (res != null)
MessageBox.Show(res);
RefreshInstances();
}
/// <summary>
/// Prompts the user for parameters to <see cref="TGServiceInterface.Components.ITGSService.CreateInstance(string, string)"/>
/// Prompts the user for parameters to <see cref="ITGInstanceManager.CreateInstance(string, string)"/>
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="EventArgs"/></param>
@@ -204,10 +223,62 @@ namespace TGControlPanel
if (instance_path == null)
return;
string res = null;
await WrapServerOp(() => { res = masterInterface.GetService().CreateInstance(instance_name, instance_path); });
await WrapServerOp(() => res = masterInterface.GetServiceComponent<ITGInstanceManager>().CreateInstance(instance_name, instance_path));
if (res != null)
MessageBox.Show(res);
RefreshInstances();
}
/// <summary>
/// Attempts to connect the user to an <see cref="ITGInstance"/> based on the <see cref="ListBox.SelectedIndex"/> of <see cref="InstanceListBox"/>
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="EventArgs"/></param>
void ConnectButton_Click(object sender, EventArgs e)
{
TryConnectToIndexInstance(InstanceListBox.SelectedIndex);
}
/// <summary>
/// Prompts the user if they want to call <see cref="ITGInstanceManager.SetInstanceEnabled(string, bool)"/> to either online or offline an <see cref="ITGInstance"/> based on its current state
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="EventArgs"/></param>
async void EnabledCheckBox_CheckedChanged(object sender, EventArgs e)
{
if (UpdatingEnabledCheckbox)
return;
var enabling = EnabledCheckBox.Checked;
try
{
if (MessageBox.Show(String.Format("Are you sure you want to {0} this instance?", enabling ? "online" : "offline"), "Instance Status Change", MessageBoxButtons.YesNo) != DialogResult.Yes)
return;
string res = null;
var index = InstanceListBox.SelectedIndex;
await WrapServerOp(() => res = masterInterface.GetServiceComponent<ITGInstanceManager>().SetInstanceEnabled(InstanceData[index].Name, enabling));
if (res != null)
MessageBox.Show(res);
}
finally
{
RefreshInstances();
}
}
/// <summary>
/// Update <see cref="EnabledCheckBox"/> based on the selected <see cref="ITGInstance"/>'s <see cref="InstanceMetadata.Enabled"/> property
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="EventArgs"/></param>
void InstanceListBox_SelectedIndexChanged(object sender, EventArgs e)
{
var index = InstanceListBox.SelectedIndex;
if (index != ListBox.NoMatches)
{
UpdatingEnabledCheckbox = true;
EnabledCheckBox.Checked = InstanceData[index].Enabled;
UpdatingEnabledCheckbox = false;
}
}
}
}
+3 -23
View File
@@ -4,7 +4,7 @@ using TGServiceInterface;
namespace TGControlPanel
{
partial class Login : CountedForm
sealed partial class Login : CountedForm
{
/// <summary>
/// Create a <see cref="Login"/> form
@@ -73,28 +73,8 @@ namespace TGControlPanel
MessageBox.Show("Authentication error: Username/password/windows identity is not authorized! Ensure you are a system administrator or in the correct Windows group on the service machine.");
return;
}
if (!res.HasFlag(ConnectivityLevel.Administrator))
{
while (true)
{
var InstanceToConnectTo = Program.TextPrompt("Select instance", "You do not have permission to list server instances. Please enter the name of the instance to connect to:");
if (InstanceToConnectTo == null)
return;
res = I.ConnectToInstance(InstanceToConnectTo);
if (!res.HasFlag(ConnectivityLevel.Connected))
MessageBox.Show("Unable to connect to instance! Does it exist?");
else if (!res.HasFlag(ConnectivityLevel.Authenticated))
MessageBox.Show("The current user is not authorized to access this instance!");
else
break;
}
new ControlPanel(I).Show();
}
else
new InstanceSelector(I).Show();
new InstanceSelector(I).Show();
Close();
}
catch
+2 -2
View File
@@ -73,7 +73,7 @@ namespace TGInstallerWrapper
var verifiedConnection = Interface.ConnectionStatus().HasFlag(ConnectivityLevel.Administrator);
try
{
VersionLabel.Text = Interface.GetService().Version();
VersionLabel.Text = Interface.GetServiceComponent<ITGSService>().Version();
var isV0 = VersionLabel.Text.Contains("v3.0");
if (isV0) //OH GOD!!!!
MessageBox.Show("Upgrading from version 3.0 may trigger a bug that can delete /config and /data. IT IS STRONGLY RECCOMMENDED THAT YOU BACKUP THESE FOLDERS BEFORE UPDATING!", "Warning");
@@ -98,7 +98,7 @@ namespace TGInstallerWrapper
var connectionVerified = Interface.ConnectionStatus().HasFlag(ConnectivityLevel.Administrator);
try
{
Interface.GetService().PrepareForUpdate();
Interface.GetServiceComponent<ITGSService>().PrepareForUpdate();
Thread.Sleep(3000); //chat messages
return true;
}
+1 -1
View File
@@ -20,7 +20,7 @@ namespace TGServerService
public static IInstanceConfig CreateFromNETSettings()
{
var Config = Properties.Settings.Default;
var result = new DeprecatedInstanceConfig(LoadPreviousNetPropertyOrDefault("ServerDirectory", "C:\\tgstation-server-3"));
var result = new DeprecatedInstanceConfig(Program.NormalizePath(LoadPreviousNetPropertyOrDefault("ServerDirectory", "C:\\tgstation-server-3")));
// using nameof for sanity where possible
result.ProjectName = LoadPreviousNetPropertyOrDefault(nameof(ProjectName), result.ProjectName);
result.Port = LoadPreviousNetPropertyOrDefault("ServerPort", result.Port);
+12
View File
@@ -175,5 +175,17 @@ namespace TGServerService
{
return input.Replace("%", "%25").Replace("=", "%3d").Replace(";", "%3b").Replace("&", "%26").Replace("+", "%2b");
}
/// <summary>
/// Normalizes different versions of a path <see cref="string"/>
/// </summary>
/// <param name="path">The path to normalize</param>
/// <returns>The normalized path</returns>
public static string NormalizePath(string path)
{
return Path.GetFullPath(new Uri(path).LocalPath)
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
.ToUpperInvariant();
}
}
}
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Principal;
using System.ServiceModel;
using TGServiceInterface.Components;
@@ -9,21 +11,23 @@ namespace TGServerService
/// <summary>
/// A <see cref="ServiceAuthorizationManager"/> used to determine only if the caller is an admin
/// </summary>
sealed class AdministrativeAuthorizationManager : ServiceAuthorizationManager
sealed class RootAuthorizationManager : ServiceAuthorizationManager
{
string LastSeenUser;
public static readonly IList<ServiceAuthorizationManager> InstanceAuthManagers = new List<ServiceAuthorizationManager>();
protected override bool CheckAccessCore(OperationContext operationContext)
{
var contract = operationContext.EndpointDispatcher.ContractName;
if (contract == typeof(ITGConnectivity).Name) //always allow connectivity checks
return true;
var windowsIdent = operationContext.ServiceSecurityContext.WindowsIdentity;
var wp = new WindowsPrincipal(windowsIdent);
//first allow admins
var authSuccess = wp.IsInRole(WindowsBuiltInRole.Administrator);
if(!authSuccess && contract == typeof(ITGLanding).Name)
return InstanceAuthManagers.FirstOrDefault(x => x.CheckAccess(operationContext)) != null;
var user = windowsIdent.Name;
if (LastSeenUser != user)
@@ -73,6 +73,7 @@ namespace TGServerService
/// <returns>The name of the group allowed to access the <see cref="ServerInstance"/> if it could be found, <see langword="null"/> otherwise</returns>
string FindTheDroidsWereLookingFor(string search = null, bool useDomain = false)
{
RootAuthorizationManager.InstanceAuthManagers.Add(this);
//find the group that is authorized to use the tools
var pc = new PrincipalContext(useDomain ? ContextType.Domain : ContextType.Machine);
var groupName = search ?? Config.AuthorizedUserGroupSID;
@@ -95,6 +96,14 @@ namespace TGServerService
}
return gp.Name;
}
/// <summary>
/// Cleans up the <see cref="ITGAdministration"/> component
/// </summary>
void DisposeAdministration()
{
RootAuthorizationManager.InstanceAuthManagers.Remove(this);
}
/// <summary>
/// Called by WCF whenever a component call is made. Checks to see that the supplied user account has access to the requested component
@@ -51,6 +51,7 @@ namespace TGServerService
DisposeByond();
DisposeRepo();
DisposeChat();
DisposeAdministration();
Config.Save();
}
+16 -23
View File
@@ -15,7 +15,7 @@ namespace TGServerService
/// The windows service the application runs as
/// </summary>
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
class Service : ServiceBase, ITGSService, ITGConnectivity
class Service : ServiceBase, ITGSService, ITGConnectivity, ITGLanding, ITGInstanceManager
{
/// <summary>
/// The logging ID used for <see cref="Service"/> events
@@ -233,9 +233,9 @@ namespace TGServerService
void SetupService()
{
serviceHost = CreateHost(this, Interface.MasterInterfaceName);
AddEndpoint(serviceHost, typeof(ITGSService));
AddEndpoint(serviceHost, typeof(ITGConnectivity));
serviceHost.Authorization.ServiceAuthorizationManager = new AdministrativeAuthorizationManager(); //only admins can diddle us
foreach (var I in Interface.ValidServiceInterfaces)
AddEndpoint(serviceHost, I);
serviceHost.Authorization.ServiceAuthorizationManager = new RootAuthorizationManager(); //only admins can diddle us
}
/// <summary>
@@ -277,7 +277,7 @@ namespace TGServerService
WriteEntry(String.Format("Instance at {0} has a duplicate name! Detaching...", I.Directory), EventID.InstanceInitializationFailure, EventLogEntryType.Error, LoggingID);
pathsToRemove.Add(I.Directory);
}
if (SetupInstance(I) == null)
if (I.Enabled && SetupInstance(I) == null)
pathsToRemove.Add(I.Directory);
else
seenNames.Add(I.Name);
@@ -331,7 +331,6 @@ namespace TGServerService
{
var datInstance = ((ServerInstance)hosts[config.Directory].SingletonInstance);
WriteEntry(String.Format("Unable to start instance at path {0}. Has the same name as instance at path {1}. Detaching...", config.Directory, datInstance.ServerDirectory()), EventID.InstanceInitializationFailure, EventLogEntryType.Error, LoggingID);
Properties.Settings.Default.InstancePaths.Remove(config.Directory);
return null;
}
if (!config.Enabled)
@@ -350,7 +349,7 @@ namespace TGServerService
var host = CreateHost(instance, String.Format("{0}/{1}", Interface.InstanceInterfaceName, instanceName));
hosts.Add(instanceName, host);
foreach (var J in Interface.ValidInterfaces)
foreach (var J in Interface.ValidInstanceInterfaces)
AddEndpoint(host, J);
host.Authorization.ServiceAuthorizationManager = instance;
@@ -471,6 +470,7 @@ namespace TGServerService
/// <inheritdoc />
public string CreateInstance(string Name, string path)
{
path = Program.NormalizePath(path);
var res = CheckInstanceName(Name);
if (res != null)
return res;
@@ -510,6 +510,8 @@ namespace TGServerService
/// <returns><see langword="null"/> on success, error message on failure</returns>
string SetupOneInstance(IInstanceConfig config)
{
if (!config.Enabled)
return null;
try
{
var host = SetupInstance(config);
@@ -529,6 +531,7 @@ namespace TGServerService
/// <inheritdoc />
public string ImportInstance(string path)
{
path = Program.NormalizePath(path);
var Config = Properties.Settings.Default;
lock (this)
{
@@ -587,24 +590,14 @@ namespace TGServerService
{
if (hostIsOnline)
return null;
//now this is a bit awkward because we need to check each instance config for the one named Name
string LastCheckedConfig = null;
try
{
foreach (var ic in GetInstanceConfigs())
foreach (var ic in GetInstanceConfigs())
if (ic.Name == Name)
{
if (ic.Name == Name)
{
path = ic.Directory;
ic.Enabled = true;
return SetupOneInstance(ic);
}
path = ic.Directory;
ic.Enabled = true;
ic.Save();
return SetupOneInstance(ic);
}
}
catch (Exception e)
{
return String.Format("An error occurred while checking instance config at {0}! Error: ", LastCheckedConfig, e.ToString());
}
return String.Format("Instance {0} does not exist!", Name);
}
else
+1 -1
View File
@@ -95,7 +95,7 @@
<Compile Include="ChatCommands\RootChatCommand.cs" />
<Compile Include="ChatCommands\ServerChatCommand.cs" />
<Compile Include="ChatCommands\VersionCommand.cs" />
<Compile Include="AdministrativeAuthorizationManager.cs" />
<Compile Include="RootAuthorizationManager.cs" />
<Compile Include="DeprecatedInstanceConfig.cs" />
<Compile Include="InstanceConfig.cs" />
<Compile Include="MessageType.cs" />
@@ -13,12 +13,5 @@ namespace TGServiceInterface.Components
/// </summary>
[OperationContract]
void VerifyConnection();
/// <summary>
/// Retrieve's the service's version
/// </summary>
/// <returns>The service's version</returns>
[OperationContract]
string Version();
}
}
@@ -14,5 +14,12 @@ namespace TGServiceInterface.Components
/// <returns>The path to the directory on success, null on failure</returns>
[OperationContract]
string ServerDirectory();
/// <summary>
/// Retrieve's the service's version
/// </summary>
/// <returns>The service's version</returns>
[OperationContract]
string Version();
}
}
@@ -0,0 +1,62 @@
using System.ServiceModel;
namespace TGServiceInterface.Components
{
/// <summary>
/// Used for managing <see cref="ITGInstance"/>s
/// </summary>
[ServiceContract]
public interface ITGInstanceManager
{
/// <summary>
/// Creates a new <see cref="ITGInstance"/>
/// </summary>
/// <param name="Name">The name of the instance</param>
/// <param name="path">The path to the instance</param>
/// <returns><see langword="null"/> on success, error message on failure</returns>
[OperationContract]
string CreateInstance(string Name, string path);
/// <summary>
/// Registers an existing server instance
/// </summary>
/// <param name="path">The path to the instance</param>
/// <returns><see langword="null"/> on success, error message on failure</returns>
[OperationContract]
string ImportInstance(string path);
/// <summary>
/// Checks if an instance is online
/// </summary>
/// <param name="Name">The name of the instance</param>
/// <returns><see langword="true"/> if the Instance exists and is online, <see langword="false"/> otherwise</returns>
[OperationContract]
bool InstanceEnabled(string Name);
/// <summary>
/// Sets an instance's enabled status
/// </summary>
/// <param name="Name">The instance whom's status should be changed</param>
/// <param name="enabled"><see langword="true"/> to enable the instance, <see langword="false"/> to disable it</param>
/// <returns><see langword="null"/> on success, error message on failure</returns>
[OperationContract]
string SetInstanceEnabled(string Name, bool enabled);
/// <summary>
/// Renames an instance, this will restart the instance if it is enabled
/// </summary>
/// <param name="name">The current name of the instance</param>
/// <param name="new_name">The new name of the instance</param>
/// <returns><see langword="null"/> on success, error message on failure</returns>
[OperationContract]
string RenameInstance(string name, string new_name);
/// <summary>
/// Disables and unregisters an instance, allowing the folder and data to be manipulated manually
/// </summary>
/// <param name="name">The instance to detach</param>
/// <returns><see langword="null"/> on success, error message on failure</returns>
[OperationContract]
string DetachInstance(string name);
}
}
+26
View File
@@ -0,0 +1,26 @@
using System.Collections.Generic;
using System.ServiceModel;
namespace TGServiceInterface.Components
{
/// <summary>
/// Used for general authentication and listing <see cref="ITGInstance"/>s
/// </summary>
[ServiceContract]
public interface ITGLanding
{
/// <summary>
/// Retrieve's the service's version
/// </summary>
/// <returns>The service's version</returns>
[OperationContract]
string Version();
/// <summary>
/// List instances that the caller can access
/// </summary>
/// <returns>A <see cref="IDictionary{TKey, TValue}"/> of instance names relating to their paths</returns>
[OperationContract]
IList<InstanceMetadata> ListInstances();
}
}
+3 -61
View File
@@ -16,13 +16,6 @@ namespace TGServiceInterface.Components
[OperationContract]
void PrepareForUpdate();
/// <summary>
/// Retrieve's the service's version
/// </summary>
/// <returns>The service's version</returns>
[OperationContract]
string Version();
/// <summary>
/// Get the port used for remote operation
/// </summary>
@@ -40,62 +33,11 @@ namespace TGServiceInterface.Components
string SetRemoteAccessPort(ushort port);
/// <summary>
/// List instances
/// Retrieve's the service's version
/// </summary>
/// <returns>A <see cref="IDictionary{TKey, TValue}"/> of instance names relating to their paths</returns>
/// <returns>The service's version</returns>
[OperationContract]
IList<InstanceMetadata> ListInstances();
/// <summary>
/// Creates a new server instance
/// </summary>
/// <param name="Name">The name of the instance</param>
/// <param name="path">The path to the instance</param>
/// <returns><see langword="null"/> on success, error message on failure</returns>
[OperationContract]
string CreateInstance(string Name, string path);
/// <summary>
/// Registers an existing server instance
/// </summary>
/// <param name="path">The path to the instance</param>
/// <returns><see langword="null"/> on success, error message on failure</returns>
[OperationContract]
string ImportInstance(string path);
/// <summary>
/// Checks if an instance is online
/// </summary>
/// <param name="Name">The name of the instance</param>
/// <returns><see langword="true"/> if the Instance exists and is online, <see langword="false"/> otherwise</returns>
[OperationContract]
bool InstanceEnabled(string Name);
/// <summary>
/// Sets an instance's enabled status
/// </summary>
/// <param name="Name">The instance whom's status should be changed</param>
/// <param name="enabled"><see langword="true"/> to enable the instance, <see langword="false"/> to disable it</param>
/// <returns><see langword="null"/> on success, error message on failure</returns>
[OperationContract]
string SetInstanceEnabled(string Name, bool enabled);
/// <summary>
/// Renames an instance, this will restart the instance if it is enabled
/// </summary>
/// <param name="name">The current name of the instance</param>
/// <param name="new_name">The new name of the instance</param>
/// <returns><see langword="null"/> on success, error message on failure</returns>
[OperationContract]
string RenameInstance(string name, string new_name);
/// <summary>
/// Disables and unregisters an instance, allowing the folder and data to be manipulated manually
/// </summary>
/// <param name="name">The instance to detach</param>
/// <returns><see langword="null"/> on success, error message on failure</returns>
[OperationContract]
string DetachInstance(string name);
string Version();
/// <summary>
/// Sets the path to the python 2.7 installation
+23 -17
View File
@@ -52,17 +52,17 @@ namespace TGServiceInterface
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
/// Returns the requested <see cref="IInterface"/> component <see langword="interface"/> for the instance <see cref="InstanceName"/>. This does not guarantee a successful connection.
/// </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
/// Returns a root service component
/// </summary>
/// <returns>The <see cref="ITGSService"/> component for the service</returns>
ITGSService GetService();
T GetServiceComponent<T>();
/// <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
@@ -82,9 +82,14 @@ namespace TGServiceInterface
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}"/>
/// List of <see langword="interface"/>s that can be used with <see cref="GetServiceComponent{T}"/>
/// </summary>
public static readonly IList<Type> ValidInterfaces = CollectComponents();
public static readonly IList<Type> ValidServiceInterfaces = new List<Type> { typeof(ITGSService), typeof(ITGInstanceManager), typeof(ITGConnectivity), typeof(ITGLanding) };
/// <summary>
/// List of <see langword="interface"/>s that can be used with <see cref="GetComponent{T}"/>
/// </summary>
public static readonly IList<Type> ValidInstanceInterfaces = CollectComponents();
/// <summary>
/// The maximum message size to and from a local server
@@ -145,13 +150,13 @@ namespace TGServiceInterface
/// <returns>A <see cref="IList{T}"/> of <see langword="interface"/> <see cref="Type"/>s that can be used with the service</returns>
static IList<Type> CollectComponents()
{
var ServiceComponent = typeof(ITGSService); //this is special
//find all interfaces in this assembly in this namespace that have the service contract attribute
var ConnectivityComponent = typeof(ITGConnectivity);
//find all interfaces in this assembly in this namespace that have the service contract attribute
var query = from t in Assembly.GetExecutingAssembly().GetTypes()
where t.IsInterface
&& t.Namespace == ServiceComponent.Namespace
&& t.Namespace == ConnectivityComponent.Namespace
&& t.GetCustomAttribute(typeof(ServiceContractAttribute)) != null
&& t != ServiceComponent
&& (t == ConnectivityComponent || !ValidServiceInterfaces.Contains(t))
select t;
return query.ToList();
}
@@ -288,7 +293,7 @@ namespace TGServiceInterface
/// <inheritdoc />
public bool VersionMismatch(out string errorMessage)
{
var splits = GetService().Version().Split(' ');
var splits = GetServiceComponent<ITGLanding>().Version().Split(' ');
var theirs = new Version(splits[splits.Length - 1].Substring(1));
var ours = new Version(FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).FileVersion);
if(theirs.Major != ours.Major || theirs.Minor != ours.Minor || theirs.Revision != ours.Revision) //don't care about the patch level
@@ -314,7 +319,7 @@ namespace TGServiceInterface
public T GetComponent<T>()
{
var ToT = typeof(T);
if (!ValidInterfaces.Contains(ToT) && ToT != typeof(ITGSService))
if (!ValidInstanceInterfaces.Contains(ToT))
throw new Exception("Invalid type!");
return GetComponentImpl<T>(true);
}
@@ -357,9 +362,12 @@ namespace TGServiceInterface
}
/// <inheritdoc />
public ITGSService GetService()
public T GetServiceComponent<T>()
{
return GetComponentImpl<ITGSService>(false);
var ToT = typeof(T);
if (!ValidServiceInterfaces.Contains(ToT))
throw new Exception("Invalid type!");
return GetComponentImpl<T>(false);
}
/// <summary>
@@ -420,10 +428,9 @@ namespace TGServiceInterface
error = e.ToString();
return ConnectivityLevel.None;
}
var service = GetService();
try
{
service.Version();
GetServiceComponent<ITGLanding>().Version();
}
catch(Exception e)
{
@@ -432,8 +439,7 @@ namespace TGServiceInterface
}
try
{
// TODO
GetServiceComponent<ITGSService>().Version();
error = null;
return ConnectivityLevel.Administrator;
}
@@ -57,6 +57,8 @@
<Compile Include="Components\DreamDaemon.cs" />
<Compile Include="Components\Chat.cs" />
<Compile Include="Components\Instance.cs" />
<Compile Include="Components\InstanceManager.cs" />
<Compile Include="Components\Landing.cs" />
<Compile Include="Enumerations.cs" />
<Compile Include="Helpers.cs" />
<Compile Include="InstanceMetadata.cs" />