|
|
|
@@ -7,10 +7,13 @@ using System.Security.Principal;
|
|
|
|
|
using System.ServiceModel;
|
|
|
|
|
namespace TGServiceInterface
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Main inteface class for the service
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class Server
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// List of types that can be used with GetComponen
|
|
|
|
|
/// List of <see langword="interface"/>s that can be used with GetComponen
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static readonly IList<Type> ValidInterfaces = new List<Type> { typeof(ITGByond), typeof(ITGChat), typeof(ITGCompiler), typeof(ITGConfig), typeof(ITGDreamDaemon), typeof(ITGRepository), typeof(ITGSService), typeof(ITGConnectivity), typeof(ITGAdministration), typeof(ITGInterop) };
|
|
|
|
|
|
|
|
|
@@ -50,7 +53,15 @@ namespace TGServiceInterface
|
|
|
|
|
/// </summary>
|
|
|
|
|
static string HTTPSPassword;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Associated list of open <see cref="ChannelFactory"/>s keyed by <see langword="interface"/> type. A <see cref="ChannelFactory"/> in this list may close or fault at any time. Must be locked before being accessed
|
|
|
|
|
/// </summary>
|
|
|
|
|
static Dictionary<Type, ChannelFactory> ChannelFactoryCache = new Dictionary<Type, ChannelFactory>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sets the function called when a remote login fails due to the server having an invalid SSL cert
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="handler">The <see cref="Func{T, TResult}"/> to be called when a remote login is attempted while the server posesses a bad certificate. Passed a <see cref="string"/> of error information about the and should return <see langword="true"/> if it the connection should be made anyway</param>
|
|
|
|
|
public static void SetBadCertificateHandler(Func<string, bool> handler)
|
|
|
|
|
{
|
|
|
|
|
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, error) =>
|
|
|
|
@@ -88,17 +99,28 @@ namespace TGServiceInterface
|
|
|
|
|
ClearCachedChannels();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Closes all <see cref="ChannelFactory"/>s stored in <see cref="ChannelFactoryCache"/> and clears it
|
|
|
|
|
/// </summary>
|
|
|
|
|
static void ClearCachedChannels()
|
|
|
|
|
{
|
|
|
|
|
foreach (var I in ChannelFactoryCache)
|
|
|
|
|
CloseChannel(I.Value);
|
|
|
|
|
ChannelFactoryCache.Clear();
|
|
|
|
|
lock (ChannelFactoryCache)
|
|
|
|
|
{
|
|
|
|
|
foreach (var I in ChannelFactoryCache)
|
|
|
|
|
CloseChannel(I.Value);
|
|
|
|
|
ChannelFactoryCache.Clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns <see langword="true"/> if the <see cref="Server"/> 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="Server"/> interface being used to connect to a service does not have the same release version as the service</returns>
|
|
|
|
|
public static bool VersionMismatch(out string errorMessage)
|
|
|
|
|
{
|
|
|
|
|
var splits = Server.GetComponent<ITGSService>().Version().Split(' ');
|
|
|
|
|
var theirs = new Version(splits[splits.Length - 1].Substring(1));
|
|
|
|
|
var splits = Server.GetComponent<ITGSService>().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 != ours)
|
|
|
|
|
{
|
|
|
|
@@ -123,6 +145,10 @@ namespace TGServiceInterface
|
|
|
|
|
ClearCachedChannels();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Safely shuts down a single <see cref="ChannelFactory"/>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="cf"></param>
|
|
|
|
|
public static void CloseChannel(ChannelFactory cf)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
@@ -136,10 +162,10 @@ namespace TGServiceInterface
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns the requested server component interface. This does not guarantee a successful connection
|
|
|
|
|
/// Returns the requested <see cref="Server"/> component <see langword="interface"/>. 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 type of the component to retrieve</typeparam>
|
|
|
|
|
/// <returns>The correct component</returns>
|
|
|
|
|
/// <typeparam name="T">The component <see langword="interface"/> to retrieve</typeparam>
|
|
|
|
|
/// <returns>The correct component <see langword="interface"/></returns>
|
|
|
|
|
public static T GetComponent<T>()
|
|
|
|
|
{
|
|
|
|
|
var tot = typeof(T);
|
|
|
|
@@ -166,6 +192,12 @@ namespace TGServiceInterface
|
|
|
|
|
return cf.CreateChannel();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Directly creates a <see cref="ChannelFactory{TChannel}"/> for <typeparamref name="T"/> without caching. This should be eventually closed by the caller
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="T">The component <see langword="interface"/> of the channel to be created</typeparam>
|
|
|
|
|
/// <returns>The correct <see cref="ChannelFactory{TChannel}"/></returns>
|
|
|
|
|
/// <exception cref="Exception">Thrown if <typeparamref name="T"/> isn't a valid component <see langword="interface"/></exception>
|
|
|
|
|
public static ChannelFactory<T> CreateChannel<T>()
|
|
|
|
|
{
|
|
|
|
|
var ToT = typeof(T);
|
|
|
|
@@ -201,11 +233,9 @@ namespace TGServiceInterface
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Used to test if the service is avaiable on the machine
|
|
|
|
|
/// Note that state can technically change at any time
|
|
|
|
|
/// and any call to the service may throw an exception because it failed
|
|
|
|
|
/// Used to test if the service is avaiable on the machine. Note that state can technically change at any time and any call to the service may throw an exception because it failed
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>null on successful connection, error message on failure</returns>
|
|
|
|
|
/// <returns><see langword="null"/> on successful connection, error message <see cref="string"/> on failure</returns>
|
|
|
|
|
public static string VerifyConnection()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
@@ -220,10 +250,9 @@ namespace TGServiceInterface
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// As opposed to VerifyConnection(), this check user credentials
|
|
|
|
|
/// Requires a prior call to <see cref="VerifyConnection"/>
|
|
|
|
|
/// Checks if the supplied user's credentials have permission to use the service. Requires a successful prior call to <see cref="VerifyConnection"/>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>true if credentials are valid, false otherwise</returns>
|
|
|
|
|
/// <returns><see langword="true"/> if credentials are valid, <see langword="false"/> otherwise</returns>
|
|
|
|
|
public static bool Authenticate()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
@@ -238,10 +267,9 @@ namespace TGServiceInterface
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// As opposed to Authentication() this returns true if the current login can use the <see cref="ITGAdministration"/> interface.
|
|
|
|
|
/// Requires a prior call to <see cref="Authenticate"/>
|
|
|
|
|
/// Checks if the current login can use <see cref="ITGAdministration"/>. Requires a successful prior call to <see cref="Authenticate"/>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>true if the connection may use the <see cref="ITGAdministration"/> interface, false otherwise</returns>
|
|
|
|
|
/// <returns><see langword="true"/> if the connection may use <see cref="ITGAdministration"/>, <see langword="false"/> otherwise</returns>
|
|
|
|
|
public static bool AuthenticateAdmin()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|