Merge pull request #578 from Cyberboss/YeahButItsNotRunning

Formatting Cleanup
This commit is contained in:
Jordan Brown
2018-08-25 09:14:58 -04:00
committed by GitHub
91 changed files with 293 additions and 251 deletions
+20 -20
View File
@@ -63,7 +63,7 @@ namespace Tgstation.Server.Api
/// <summary>
/// The client's user agent
/// </summary>
public ProductHeaderValue UserAgent { get; }
public ProductHeaderValue UserAgent { get; }
/// <summary>
/// The client's API version
@@ -102,13 +102,13 @@ namespace Tgstation.Server.Api
/// </summary>
/// <param name="userAgent">The value of <see cref="UserAgent"/></param>
/// <param name="token">The value of <see cref="Token"/></param>
public ApiHeaders(ProductHeaderValue userAgent, string token) : this(userAgent, token, null, null)
{
if (userAgent == null)
throw new ArgumentNullException(nameof(userAgent));
if (token == null)
throw new ArgumentNullException(nameof(token));
}
public ApiHeaders(ProductHeaderValue userAgent, string token) : this(userAgent, token, null, null)
{
if (userAgent == null)
throw new ArgumentNullException(nameof(userAgent));
if (token == null)
throw new ArgumentNullException(nameof(token));
}
/// <summary>
/// Construct <see cref="ApiHeaders"/> for password authentication
@@ -117,21 +117,21 @@ namespace Tgstation.Server.Api
/// <param name="username">The value of <see cref="Username"/></param>
/// <param name="password">The value of <see cref="Password"/></param>
public ApiHeaders(ProductHeaderValue userAgent, string username, string password) : this(userAgent, null, username, password)
{
if (userAgent == null)
throw new ArgumentNullException(nameof(userAgent));
if (username == null)
throw new ArgumentNullException(nameof(username));
if (password == null)
throw new ArgumentNullException(nameof(password));
}
{
if (userAgent == null)
throw new ArgumentNullException(nameof(userAgent));
if (username == null)
throw new ArgumentNullException(nameof(username));
if (password == null)
throw new ArgumentNullException(nameof(password));
}
/// <summary>
/// Construct and validates <see cref="ApiHeaders"/> from a set of <paramref name="requestHeaders"/>
/// </summary>
/// <param name="requestHeaders">The <see cref="RequestHeaders"/> containing the <see cref="ApiHeaders"/></param>
public ApiHeaders(RequestHeaders requestHeaders)
{
{
var jsonAccept = new Microsoft.Net.Http.Headers.MediaTypeHeaderValue(ApplicationJson);
if (!requestHeaders.Accept.Any(x => x.MediaType == jsonAccept.MediaType))
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Client does not accept {0}!", ApplicationJson));
@@ -142,7 +142,7 @@ namespace Tgstation.Server.Api
//assure the client user agent has a name and version
if (String.IsNullOrWhiteSpace(clientUserAgent.Product.Name) || !Version.TryParse(clientUserAgent.Product.Version, out var clientVersion))
throw new InvalidOperationException("Malformed client user agent!");
//make sure the api header matches ours
if (!requestHeaders.Headers.TryGetValue(ApiVersionHeader, out var apiUserAgentHeaderValues) || !ProductInfoHeaderValue.TryParse(apiUserAgentHeaderValues.FirstOrDefault(), out var apiUserAgent) || apiUserAgent.Product.Name != assemblyName.Name)
throw new InvalidOperationException("Missing API version!");
@@ -166,7 +166,7 @@ namespace Tgstation.Server.Api
if (String.IsNullOrEmpty(parameter))
throw new InvalidOperationException("Missing authentication parameter!");
if(requestHeaders.Headers.TryGetValue(instanceIdHeader, out var instanceIdValues))
if (requestHeaders.Headers.TryGetValue(instanceIdHeader, out var instanceIdValues))
{
var instanceIdString = instanceIdValues.FirstOrDefault();
if (instanceIdString != default && Int64.TryParse(instanceIdString, out var instanceId))
@@ -243,5 +243,5 @@ namespace Tgstation.Server.Api
if (instanceId.HasValue)
headers.Add(instanceIdHeader, instanceId.ToString());
}
}
}
}
@@ -2,10 +2,10 @@
namespace Tgstation.Server.Api.Models
{
/// <summary>
/// Represents the state of the DreamMaker compiler. Create action starts a new compile. Delete action cancels the current compile
/// </summary>
public sealed class DreamMaker : DreamMakerSettings
/// <summary>
/// Represents the state of the DreamMaker compiler. Create action starts a new compile. Delete action cancels the current compile
/// </summary>
public sealed class DreamMaker : DreamMakerSettings
{
/// <summary>
/// The <see cref="CompilerStatus"/> of the compiler
@@ -3,11 +3,11 @@
/// <summary>
/// For editing a given <see cref="User"/>. Will never be returned by the API
/// </summary>
public sealed class UserUpdate : User
public sealed class UserUpdate : User
{
/// <summary>
/// Cleartext password of the <see cref="User"/>
/// </summary>
public string Password { get; set; }
}
}
}
@@ -12,13 +12,13 @@ namespace Tgstation.Server.Api.Rights
/// User has no rights
/// </summary>
None = 0,
/// <summary>
/// Allow read access to <see cref="Models.InstanceUser"/> for the <see cref="Models.Instance"/>
/// </summary>
ReadUsers = 1,
/// <summary>
/// Allow write access to <see cref="Models.InstanceUser"/> for the <see cref="Models.Instance"/>
/// </summary>
WriteUsers = 2
}
/// <summary>
/// Allow read access to <see cref="Models.InstanceUser"/> for the <see cref="Models.Instance"/>
/// </summary>
ReadUsers = 1,
/// <summary>
/// Allow write access to <see cref="Models.InstanceUser"/> for the <see cref="Models.Instance"/>
/// </summary>
WriteUsers = 2
}
}
@@ -39,7 +39,7 @@ namespace Tgstation.Server.Api.Rights
/// <typeparam name="TRight">The <see cref="RightsType"/></typeparam>
/// <param name="right">The <typeparamref name="TRight"/></param>
/// <returns>A <see cref="string"/> representing the claim role name</returns>
public static string RoleNames<TRight>(TRight right) where TRight: Enum
public static string RoleNames<TRight>(TRight right) where TRight : Enum
{
var flags = new List<string>();
IEnumerable<string> GetRoleNames()
@@ -18,7 +18,8 @@ namespace Tgstation.Server.Client
{
Message = "An unknown API error occurred!",
SeverApiVersion = null
}, statusCode) { }
}, statusCode)
{ }
/// <summary>
/// Construct an <see cref="ApiConflictException"/>
@@ -7,7 +7,7 @@ namespace Tgstation.Server.Client.Components
/// <summary>
/// For managing the compiler
/// </summary>
public interface IDreamMakerClient
public interface IDreamMakerClient
{
/// <summary>
/// Get the <see cref="DreamMaker"/> information
@@ -52,5 +52,5 @@ namespace Tgstation.Server.Client.Components
/// Access the <see cref="IJobsClient"/>
/// </summary>
IJobsClient Jobs { get; }
}
}
}
@@ -5,10 +5,10 @@ using Tgstation.Server.Api.Models;
namespace Tgstation.Server.Client.Components
{
/// <summary>
/// For managing <see cref="InstanceUser"/>s
/// </summary>
public interface IInstanceUserClient
/// <summary>
/// For managing <see cref="InstanceUser"/>s
/// </summary>
public interface IInstanceUserClient
{
/// <summary>
/// Get the <see cref="InstanceUser"/> associated with the logged on user
@@ -9,8 +9,8 @@ namespace Tgstation.Server.Client.Components
/// <summary>
/// Access to running jobs
/// </summary>
public interface IJobsClient
{
public interface IJobsClient
{
/// <summary>
/// List the <see cref="Api.Models.Internal.Job.Id"/>s in the <see cref="Instance"/>
/// </summary>
@@ -27,7 +27,7 @@ namespace Tgstation.Server.Client.Components
public InstanceUserClient(IApiClient apiClient, Instance instance)
{
this.apiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient));
this.instance = instance ?? throw new ArgumentNullException(nameof(instance));
this.instance = instance ?? throw new ArgumentNullException(nameof(instance));
}
/// <inheritdoc />
@@ -50,7 +50,7 @@ namespace Tgstation.Server.Client.Components
{
await Task.Delay(requeryRate, cancellationToken).ConfigureAwait(false);
job = await Read(job, cancellationToken).ConfigureAwait(false);
if(job.Progress.HasValue && job.Progress != lastProgress)
if (job.Progress.HasValue && job.Progress != lastProgress)
{
progressCallback(job.Progress.Value);
lastProgress = job.Progress;
@@ -16,7 +16,7 @@ namespace Tgstation.Server.Client
/// <param name="statusCode">The <see cref="HttpStatusCode"/> for the <see cref="ClientException"/></param>
public ConflictException(ErrorMessage errorMessage, HttpStatusCode statusCode) : base(errorMessage, statusCode)
{ }
/// <summary>
/// Construct a <see cref="ConflictException"/>
/// </summary>
+18 -2
View File
@@ -1,4 +1,5 @@
using System.Threading;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models;
@@ -13,9 +14,24 @@ namespace Tgstation.Server.Client
/// Read the current user's information and general rights
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns></returns>
/// <returns>A <see cref="Task{TResult}"/> resulting in the current <see cref="User"/></returns>
Task<User> Read(CancellationToken cancellationToken);
/// <summary>
/// Get a specific <paramref name="user"/>
/// </summary>
/// <param name="user">The <see cref="User"/> to get</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in the requested <paramref name="user"/></returns>
Task<User> GetId(User user, CancellationToken cancellationToken);
/// <summary>
/// List all <see cref="User"/>s
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in a <see cref="IReadOnlyList{T}"/> of all <see cref="User"/>s</returns>
Task<IReadOnlyList<User>> List(CancellationToken cancellationToken);
/// <summary>
/// Create a new <paramref name="user"/>
/// </summary>
+1 -1
View File
@@ -30,7 +30,7 @@ namespace Tgstation.Server.Client
/// <inheritdoc />
public IUsersClient Users { get; }
/// <summary>
/// The <see cref="IApiClient"/> for the <see cref="ServerClient"/>
/// </summary>
@@ -28,7 +28,7 @@ namespace Tgstation.Server.Client
{
this.productHeaderValue = productHeaderValue ?? throw new ArgumentNullException(nameof(productHeaderValue));
}
/// <inheritdoc />
public async Task<IServerClient> CreateServerClient(Uri host, string username, string password, TimeSpan timeout, CancellationToken cancellationToken)
{
@@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<DebugType>Full</DebugType>
<Version>4.0.0.0-preview3</Version>
<Version>4.0.0.0-preview4</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>Cyberboss</Authors>
<Company>/tg/station 13</Company>
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api;
@@ -26,6 +27,12 @@ namespace Tgstation.Server.Client
/// <inheritdoc />
public Task<User> Create(UserUpdate user, CancellationToken cancellationToken) => apiClient.Create<UserUpdate, User>(Routes.User, user, cancellationToken);
/// <inheritdoc />
public Task<User> GetId(User user, CancellationToken cancellationToken) => apiClient.Read<User>(Routes.SetID(Routes.User, user.Id), cancellationToken);
/// <inheritdoc />
public Task<IReadOnlyList<User>> List(CancellationToken cancellationToken) => apiClient.Read<IReadOnlyList<User>>(Routes.List(Routes.User), cancellationToken);
/// <inheritdoc />
public Task<User> Read(CancellationToken cancellationToken) => apiClient.Read<User>(Routes.User, cancellationToken);
+1 -1
View File
@@ -29,7 +29,7 @@ namespace Tgstation.Server.Host.Console
var arguments = new List<string>(args);
var trace = arguments.Remove("--trace-host-watchdog");
var debug = arguments.Remove("--debug-host-watchdog");
loggerFactory.AddConsole(trace ? LogLevel.Trace : debug ? LogLevel.Debug : LogLevel.Information, true);
if (trace && debug)
@@ -45,7 +45,7 @@ namespace Tgstation.Server.Host.Service
{
if (watchdogFactory == null)
throw new ArgumentNullException(nameof(watchdogFactory));
if(loggerFactory == null)
if (loggerFactory == null)
throw new ArgumentNullException(nameof(loggerFactory));
loggerFactory.AddEventLog(new EventLogSettings
@@ -59,7 +59,7 @@ namespace Tgstation.Server.Host.Service
/// <inheritdoc />
public int MaxMessageSize => (int)EventLog.MaximumKilobytes * 1024;
/// <inheritdoc />
public void WriteEntry(string message, EventLogEntryType type, int eventID, short category) => EventLog.WriteEntry(message, type, eventID, category);
+10 -10
View File
@@ -3,17 +3,17 @@ using System.Threading.Tasks;
namespace Tgstation.Server.Host.Watchdog
{
/// <summary>
/// The watchdog for a <see cref="Host"/>
/// </summary>
/// <summary>
/// The watchdog for a <see cref="Host"/>
/// </summary>
public interface IWatchdog
{
/// <summary>
/// Run the <see cref="IWatchdog"/>
/// </summary>
/// <param name="args">The arguments for the <see cref="IWatchdog"/></param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task"/> representing the running operation</returns>
Task RunAsync(string[] args, CancellationToken cancellationToken);
/// <summary>
/// Run the <see cref="IWatchdog"/>
/// </summary>
/// <param name="args">The arguments for the <see cref="IWatchdog"/></param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task"/> representing the running operation</returns>
Task RunAsync(string[] args, CancellationToken cancellationToken);
}
}
@@ -52,13 +52,14 @@ namespace Tgstation.Server.Host.Watchdog
enumerator = enumerator.Select(x => Path.Combine(x, exeName));
var dotnetPath = enumerator
.Where(x => {
.Where(x =>
{
logger.LogTrace("Checking for dotnet at {0}", x);
return File.Exists(x);
})
})
.FirstOrDefault();
if(dotnetPath == default)
if (dotnetPath == default)
{
logger.LogCritical("Unable to locate dotnet executable in PATH! Please ensure the .NET Core runtime is installed and is in your PATH!");
return;
@@ -77,7 +78,7 @@ namespace Tgstation.Server.Host.Watchdog
var sourcePath = "../../../../Tgstation.Server.Host/bin/Debug/netcoreapp2.0";
foreach (string dirPath in Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories))
Directory.CreateDirectory(dirPath.Replace(sourcePath, defaultAssemblyPath));
foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories))
File.Copy(newPath, newPath.Replace(sourcePath, defaultAssemblyPath), true);
@@ -251,7 +252,7 @@ namespace Tgstation.Server.Host.Watchdog
logger.LogInformation("Revert successful!");
}
}
catch(Exception e)
catch (Exception e)
{
logger.LogWarning("Failed to move out active host assembly! Exception: {0}", e);
}
@@ -5,11 +5,11 @@ using System.Runtime.InteropServices;
namespace Tgstation.Server.Host.Watchdog
{
/// <inheritdoc />
public sealed class WatchdogFactory : IWatchdogFactory
{
/// <inheritdoc />
[ExcludeFromCodeCoverage]
public IWatchdog CreateWatchdog(ILoggerFactory loggerFactory) => new Watchdog(loggerFactory?.CreateLogger<Watchdog>() ?? throw new ArgumentNullException(nameof(loggerFactory)));
}
/// <inheritdoc />
public sealed class WatchdogFactory : IWatchdogFactory
{
/// <inheritdoc />
[ExcludeFromCodeCoverage]
public IWatchdog CreateWatchdog(ILoggerFactory loggerFactory) => new Watchdog(loggerFactory?.CreateLogger<Watchdog>() ?? throw new ArgumentNullException(nameof(loggerFactory)));
}
}
@@ -96,7 +96,7 @@ namespace Tgstation.Server.Host.Components.Byond
if (!installed)
installedVersions.Add(versionKey, ourTcs.Task);
}
if(installed)
if (installed)
using (cancellationToken.Register(() => ourTcs.SetCanceled()))
{
await Task.WhenAny(ourTcs.Task, inProgressTask).ConfigureAwait(false);
@@ -140,7 +140,7 @@ namespace Tgstation.Server.Host.Components.Byond
//make sure to do this last because this is what tells us we have a valid version in the future
await ioManager.WriteAllBytes(ioManager.ConcatPath(versionKey, VersionFileName), Encoding.UTF8.GetBytes(version.ToString()), cancellationToken).ConfigureAwait(false);
}
catch(OperationCanceledException)
catch (OperationCanceledException)
{
throw;
}
@@ -152,7 +152,7 @@ namespace Tgstation.Server.Host.Components.Byond
ourTcs.SetResult(null);
}
catch(Exception e)
catch (Exception e)
{
lock (installedVersions)
installedVersions.Remove(versionKey);
@@ -13,7 +13,7 @@ namespace Tgstation.Server.Host.Components.Byond
/// Get the file name of the DreamDaemon executable
/// </summary>
string DreamDaemonName { get; }
/// <summary>
/// Get the file name of the DreamMaker executable
/// </summary>
@@ -20,7 +20,7 @@ namespace Tgstation.Server.Host.Components.Byond
/// <summary>
/// Path to the BYOND cache
/// </summary>
const string ByondCachePath = "~/.byond"; //TODO: Verify this is correct!!!!!
const string ByondCachePath = "~/.byond"; //TODO: Verify this is correct!!!!!
/// <inheritdoc />
public string DreamDaemonName => "DreamDaemon";
@@ -7,7 +7,7 @@ namespace Tgstation.Server.Host.Components.Chat
/// <summary>
/// Represents a <see cref="Providers.IProvider"/> channel
/// </summary>
public sealed class Channel
public sealed class Channel
{
/// <summary>
/// Backing field for <see cref="RealId"/>. Represented as a <see cref="string"/> to avoid BYOND percision loss
@@ -67,7 +67,7 @@ namespace Tgstation.Server.Host.Components.Chat
/// The initial <see cref="Models.ChatBot"/> for the <see cref="Chat"/>
/// </summary>
readonly List<Models.ChatBot> initialChatBots;
/// <summary>
/// The <see cref="ICustomCommandHandler"/> for the <see cref="ChangeChannels(long, IEnumerable{Api.Models.ChatChannel}, CancellationToken)"/>
/// </summary>
@@ -228,7 +228,7 @@ namespace Tgstation.Server.Host.Components.Chat
var command = splits[0].ToUpperInvariant();
splits.RemoveAt(0);
var arguments = String.Join(" ", splits);
try
{
async Task<ICommand> GetCommand(string commandName)
@@ -282,7 +282,7 @@ namespace Tgstation.Server.Host.Components.Chat
}
var result = await commandHandler.Invoke(arguments, message.User, cancellationToken).ConfigureAwait(false);
if(result != null)
if (result != null)
await SendMessage(result, new List<ulong> { message.User.Channel.RealId }, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
@@ -318,7 +318,7 @@ namespace Tgstation.Server.Host.Components.Chat
if (I.Value.Connected && !messageTasks.ContainsKey(I.Value))
messageTasks.Add(I.Value, I.Value.NextMessage(cancellationToken));
if(messageTasks.Count == 0)
if (messageTasks.Count == 0)
{
await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
continue;
@@ -326,7 +326,7 @@ namespace Tgstation.Server.Host.Components.Chat
//wait for a message
await Task.WhenAny(updatedTask, Task.WhenAny(messageTasks.Select(x => x.Value))).ConfigureAwait(false);
//process completed ones
foreach (var I in messageTasks.Where(x => x.Value.IsCompleted).ToList())
{
@@ -339,7 +339,7 @@ namespace Tgstation.Server.Host.Components.Chat
}
}
catch (OperationCanceledException) { }
catch(Exception e)
catch (Exception e)
{
logger.LogError("Message monitor crashed!: Exception: {0}", e);
}
@@ -438,7 +438,7 @@ namespace Tgstation.Server.Host.Components.Chat
{
if (newSettings.Enabled.Value)
await provider.Connect(cancellationToken).ConfigureAwait(false);
lock(this)
lock (this)
{
//same thread shennanigans
var oldOne = connectionsUpdated;
@@ -459,7 +459,7 @@ namespace Tgstation.Server.Host.Components.Chat
return Task.WhenAll(channelIds.Select(x =>
{
ChannelMapping channelMapping;
lock(mappedChannels)
lock (mappedChannels)
if (!mappedChannels.TryGetValue(x, out channelMapping))
return Task.CompletedTask;
IProvider provider;
@@ -13,7 +13,7 @@ namespace Tgstation.Server.Host.Components.Chat
/// The <see cref="IIOManager"/> for the <see cref="ChatFactory"/>
/// </summary>
readonly IIOManager ioManager;
/// <summary>
/// The <see cref="ILoggerFactory"/> for the <see cref="ChatFactory"/>
/// </summary>
@@ -56,7 +56,7 @@ namespace Tgstation.Server.Host.Components.Chat
IrcPasswordType? passwordType = null;
string password = null;
if(splits.Length > 4)
if (splits.Length > 4)
{
if (splits.Length < 6)
throw new InvalidOperationException("Invalid connection string!");
@@ -38,7 +38,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
/// The <see cref="DiscordSocketClient"/> for the <see cref="DiscordProvider"/>
/// </summary>
readonly DiscordSocketClient client;
/// <summary>
/// The token used for connecting to discord
/// </summary>
@@ -83,7 +83,8 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
if (!pm && !mappedChannels.Contains(e.Channel.Id))
return e.MentionedUsers.Any(x => x.Id == client.CurrentUser.Id) ? SendMessage(e.Channel.Id, "I do not respond to this channel!", default) : Task.CompletedTask;
var result = new Message {
var result = new Message
{
Content = e.Content,
User = new User
{
@@ -132,7 +133,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
logger.LogWarning("Error connecting to Discord: {0}", e);
return false;
}
return true;
}
@@ -105,7 +105,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
if (passwordType.HasValue && password == null)
throw new ArgumentNullException(nameof(password));
if(password != null && !passwordType.HasValue)
if (password != null && !passwordType.HasValue)
throw new ArgumentNullException(nameof(passwordType));
this.password = password;
@@ -308,7 +308,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
logger.LogWarning("Unable to connect to IRC: {0}", e);
}
return true;
}, cancellationToken,TaskCreationOptions.LongRunning, TaskScheduler.Current);
}, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current);
/// <inheritdoc />
public override async Task Disconnect(CancellationToken cancellationToken)
@@ -357,7 +357,8 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
foreach (var I in hs)
client.RfcJoin(I);
return (IReadOnlyList<Channel>)channels.Select(x => {
return (IReadOnlyList<Channel>)channels.Select(x =>
{
var id = channelIdCounter;
if (!channelIdMap.Any(y =>
{
@@ -378,11 +379,11 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
FriendlyName = channelIdMap[id],
IsPrivate = false,
Tag = x.Tag
};
};
}).ToList();
}
}, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current);
/// <inheritdoc />
public override Task SendMessage(ulong channelId, string message, CancellationToken cancellationToken) => Task.Factory.StartNew(() =>
{
@@ -399,7 +400,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
{
client.SendMessage(sendType, channelName, message);
}
catch(Exception e)
catch (Exception e)
{
logger.LogWarning("Unable to send to channel: {0}", e);
}
@@ -77,10 +77,14 @@ namespace Tgstation.Server.Host.Components.Compiler
/// </summary>
readonly IProcessExecutor processExecutor;
/// <summary>
/// The <see cref="IWatchdog"/> for <see cref="DreamMaker"/>
/// </summary>
readonly IWatchdog watchdog;
/// <summary>
/// The <see cref="ILogger"/> for <see cref="DreamMaker"/>
/// </summary>
readonly ILogger<DreamMaker> logger;
/// <summary>
/// Construct <see cref="DreamMaker"/>
/// </summary>
@@ -93,8 +97,9 @@ namespace Tgstation.Server.Host.Components.Compiler
/// <param name="eventConsumer">The value of <see cref="eventConsumer"/></param>
/// <param name="chat">The value of <see cref="chat"/></param>
/// <param name="processExecutor">The value of <see cref="processExecutor"/></param>
/// <param name="watchdog">The value of <see cref="watchdog"/></param>
/// <param name="logger">The value of <see cref="logger"/></param>
public DreamMaker(IByondManager byond, IIOManager ioManager, StaticFiles.IConfiguration configuration, ISessionControllerFactory sessionControllerFactory, ICompileJobConsumer compileJobConsumer, IApplication application, IEventConsumer eventConsumer, IChat chat, IProcessExecutor processExecutor, ILogger<DreamMaker> logger)
public DreamMaker(IByondManager byond, IIOManager ioManager, StaticFiles.IConfiguration configuration, ISessionControllerFactory sessionControllerFactory, ICompileJobConsumer compileJobConsumer, IApplication application, IEventConsumer eventConsumer, IChat chat, IProcessExecutor processExecutor, IWatchdog watchdog, ILogger<DreamMaker> logger)
{
this.byond = byond;
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
@@ -105,6 +110,7 @@ namespace Tgstation.Server.Host.Components.Compiler
this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer));
this.chat = chat ?? throw new ArgumentNullException(nameof(chat));
this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor));
this.watchdog = watchdog ?? throw new ArgumentNullException(nameof(watchdog));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
@@ -120,7 +126,7 @@ namespace Tgstation.Server.Host.Components.Compiler
/// <returns>A <see cref="Task{TResult}"/> resulting in <see langword="true"/> if the DMAPI was successfully validated, <see langword="false"/> otherwise</returns>
async Task<bool> VerifyApi(uint timeout, DreamDaemonSecurity securityLevel, Models.CompileJob job, IByondExecutableLock byondLock, ushort portToUse, CancellationToken cancellationToken)
{
logger.LogTrace("Verifying DMAPI...");
logger.LogTrace("Verifying DMAPI...");
var launchParameters = new DreamDaemonLaunchParameters
{
AllowWebClient = false,
@@ -267,7 +273,7 @@ namespace Tgstation.Server.Host.Components.Compiler
Status = CompilerStatus.Copying;
}
try
{
var commitInsert = revisionInformation.CommitSha.Substring(0, 7);
@@ -386,7 +392,7 @@ namespace Tgstation.Server.Host.Components.Compiler
await Task.WhenAll(symATask, symBTask).ConfigureAwait(false);
await chat.SendUpdateMessage("Deployment complete! Changes will be applied on next server reboot.", cancellationToken).ConfigureAwait(false);
await chat.SendUpdateMessage(String.Format(CultureInfo.InvariantCulture, "Deployment complete!{0}", watchdog.Running ? " Changes will be applied on next server reboot." : String.Empty), cancellationToken).ConfigureAwait(false);
logger.LogDebug("Compile complete!");
return job;
@@ -54,7 +54,7 @@
/// Parameters: Game directory path
/// </summary>
CompileComplete = 11,
/// <summary>
/// Parameters: Exit code
/// </summary>
@@ -7,8 +7,8 @@ namespace Tgstation.Server.Host.Components
/// <summary>
/// Consumes <see cref="EventType"/>s and takes the appropriate actions
/// </summary>
public interface IEventConsumer
{
public interface IEventConsumer
{
/// <summary>
/// Handle a given <paramref name="eventType"/>
/// </summary>
@@ -17,5 +17,5 @@ namespace Tgstation.Server.Host.Components
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in <see langword="true"/> if more <see cref="IEventConsumer"/> should run, <see langword="false"/> otherwise</returns>
Task<bool> HandleEvent(EventType eventType, IEnumerable<string> parameters, CancellationToken cancellationToken);
}
}
}
@@ -1,7 +1,4 @@
using Tgstation.Server.Host.Components.Watchdog;
using Tgstation.Server.Host.Core;
namespace Tgstation.Server.Host.Components
namespace Tgstation.Server.Host.Components
{
/// <summary>
/// Factory for creating <see cref="IInstance"/>s
@@ -152,7 +152,7 @@ namespace Tgstation.Server.Host.Components
commandFactory.SetWatchdog(watchdog);
try
{
var dreamMaker = new DreamMaker(byond, gameIoManager, configuration, sessionControllerFactory, dmbFactory, application, eventConsumer, chat, processExecutor, loggerFactory.CreateLogger<DreamMaker>());
var dreamMaker = new DreamMaker(byond, gameIoManager, configuration, sessionControllerFactory, dmbFactory, application, eventConsumer, chat, processExecutor, watchdog, loggerFactory.CreateLogger<DreamMaker>());
return new Instance(metadata.CloneMetadata(), repoManager, byond, dreamMaker, watchdog, chat, configuration, dmbFactory, databaseContextFactory, dmbFactory, loggerFactory.CreateLogger<Instance>());
}
@@ -95,7 +95,7 @@ namespace Tgstation.Server.Host.Components.Interop
/// </summary>
/// <param name="sender">The sender of the event</param>
/// <param name="e">The <see cref="FileSystemEventArgs"/></param>
async void HandleWrite(object sender, FileSystemEventArgs e) //this is what async void was made for
async void HandleWrite(object sender, FileSystemEventArgs e) //this is what async void was made for
{
try
{
@@ -113,11 +113,11 @@ namespace Tgstation.Server.Host.Components.Interop
};
}
catch (JsonSerializationException ex)
{
{
//file not fully written yet
logger.LogDebug("Suppressing json convert exception for command file write: {0}", ex);
return;
}
}
await (handler?.HandleInterop(command, cancellationToken) ?? Task.CompletedTask).ConfigureAwait(false);
}
@@ -1,6 +1,6 @@
namespace Tgstation.Server.Host.Components.Interop
{
static class Constants
static class Constants
{
//interop values, match them up with the appropriate api.dm
@@ -22,7 +22,7 @@ namespace Tgstation.Server.Host.Components.Interop
/// The <see cref="Api.Models.Instance.Name"/> of the owner at the time of launch
/// </summary>
public string InstanceName { get; set; }
/// <summary>
/// JSON file name that contains current active chat channel information
/// </summary>
@@ -10,7 +10,7 @@ using Tgstation.Server.Host.Core;
namespace Tgstation.Server.Host.Components
{
/// <inheritdoc />
sealed class ReattachInfoHandler: IReattachInfoHandler
sealed class ReattachInfoHandler : IReattachInfoHandler
{
/// <summary>
/// The <see cref="IDatabaseContextFactory"/> for the <see cref="ReattachInfoHandler"/>
@@ -7,7 +7,7 @@ namespace Tgstation.Server.Host.Components.Repository
/// <summary>
/// Factory for creating and loading <see cref="IRepository"/>s
/// </summary>
public interface IRepositoryManager : IDisposable
public interface IRepositoryManager : IDisposable
{
/// <summary>
/// If a <see cref="CloneRepository(Uri, string, string, string, Action{int}, CancellationToken)"/> operation is in progress
@@ -39,5 +39,5 @@ namespace Tgstation.Server.Host.Components.Repository
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task"/> representing the running operation</returns>
Task DeleteRepository(CancellationToken cancellationToken);
}
}
}
@@ -140,7 +140,7 @@ namespace Tgstation.Server.Host.Components.Repository
var prBranchName = String.Format(CultureInfo.InvariantCulture, "pr-{0}", testMergeParameters.Number);
var localBranchName = String.Format(CultureInfo.InvariantCulture, "pull/{0}/headrefs/heads/{1}", testMergeParameters.Number, prBranchName);
var Refspec = new List<string> { String.Format(CultureInfo.InvariantCulture, "pull/{0}/head:{1}", testMergeParameters.Number, prBranchName) };
var logMessage = String.Format(CultureInfo.InvariantCulture, "Merge remote pull request #{0}", testMergeParameters.Number);
@@ -177,7 +177,7 @@ namespace Tgstation.Server.Host.Components.Repository
catch (UserCancelledException) { }
cancellationToken.ThrowIfCancellationRequested();
testMergeParameters.PullRequestRevision = repository.Lookup(testMergeParameters.PullRequestRevision ?? localBranchName).Sha;
cancellationToken.ThrowIfCancellationRequested();
@@ -117,7 +117,7 @@ namespace Tgstation.Server.Host.Components.Repository
/// <inheritdoc />
public async Task<IRepository> LoadRepository(CancellationToken cancellationToken)
{
lock(this)
lock (this)
if (CloneInProgress)
throw new InvalidOperationException("The repository is being cloned!");
await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
@@ -195,7 +195,7 @@ namespace Tgstation.Server.Host.Components.StaticFiles
var path = ValidateConfigRelativePath(configurationRelativePath);
ConfigurationFile result = null;
void ReadImpl()
{
lock (this)
@@ -1,11 +1,11 @@
namespace Tgstation.Server.Host.Components.StaticFiles
{
interface IPostWriteHandler
{
interface IPostWriteHandler
{
/// <summary>
/// For handling system specific necessities after a write
/// </summary>
/// <param name="filePath">The full path to the file that was written</param>
void HandleWrite(string filePath);
}
}
}
@@ -18,7 +18,7 @@ namespace Tgstation.Server.Host.Components.StaticFiles
if (stat.st_mode.HasFlag(FilePermissions.S_IXUSR))
return;
if(Syscall.chmod(filePath, stat.st_mode | FilePermissions.S_IXUSR) != 0)
if (Syscall.chmod(filePath, stat.st_mode | FilePermissions.S_IXUSR) != 0)
throw new UnixIOException(Stdlib.GetLastError());
}
}
@@ -8,8 +8,8 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// <summary>
/// Factory for <see cref="ISessionController"/>s
/// </summary>
interface ISessionControllerFactory
{
interface ISessionControllerFactory
{
/// <summary>
/// Create a <see cref="ISessionController"/> from a freshly launch DreamDaemon instance
/// </summary>
@@ -30,5 +30,5 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in a new <see cref="ISessionController"/></returns>
Task<ISessionController> Reattach(ReattachInformation reattachInformation, CancellationToken cancellationToken);
}
}
}
@@ -5,8 +5,8 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// <summary>
/// The (absolute) state of the <see cref="Watchdog"/>
/// </summary>
sealed class MonitorState
{
sealed class MonitorState
{
/// <summary>
/// If the inactive server is being rebooted
/// </summary>
@@ -38,5 +38,5 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// </summary>
[JsonIgnore]
public ISessionController InactiveServer { get; set; }
}
}
}
@@ -3,8 +3,8 @@
/// <summary>
/// Represents the action to take when /world/Reboot() is called
/// </summary>
public enum RebootState : int
{
public enum RebootState : int
{
/// <summary>
/// Run DreamDaemon's normal reboot process
/// </summary>
@@ -17,5 +17,5 @@
/// Restart the DreamDaemon process
/// </summary>
Restart = 2
}
}
}
@@ -134,7 +134,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// The port to assign DreamDaemon when it queries for it
/// </summary>
ushort? nextPort;
/// <summary>
/// The <see cref="TaskCompletionSource{TResult}"/> that completes when DD tells us about a reboot
/// </summary>
@@ -285,12 +285,13 @@ namespace Tgstation.Server.Host.Components.Watchdog
case Constants.DMCommandNewPort:
lock (this)
{
if (!query.TryGetValue(Constants.DMParameterData, out var stringPort) || !UInt16.TryParse(stringPort, out var currentPort)) {
if (!query.TryGetValue(Constants.DMParameterData, out var stringPort) || !UInt16.TryParse(stringPort, out var currentPort))
{
/////UHHHH
logger.LogWarning("DreamDaemon sent new port command without providing it's own!");
break;
}
if (!nextPort.HasValue)
//not ready yet, so what we'll do is accept the random port DD opened on for now and change it later when we decide to
reattachInformation.Port = currentPort;
@@ -301,7 +302,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
content = new Dictionary<string, ushort> { { Constants.DMParameterData, nextPort.Value } };
reattachInformation.Port = nextPort.Value;
nextPort = null;
//we'll also get here from SetPort so complete that task
var tmpTcs = portAssignmentTcs;
portAssignmentTcs = null;
@@ -233,7 +233,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
{
if (reattachInformation == null)
throw new ArgumentNullException(nameof(reattachInformation));
var basePath = reattachInformation.IsPrimary ? reattachInformation.Dmb.PrimaryDirectory : reattachInformation.Dmb.SecondaryDirectory;
var chatJsonTrackingContext = await chat.TrackJsons(basePath, reattachInformation.ChatChannelsJson, reattachInformation.ChatCommandsJson, cancellationToken).ConfigureAwait(false);
try
@@ -190,7 +190,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
bravoServer = null;
Running = false;
}
/// <summary>
/// Implementation of <see cref="Terminate(bool, CancellationToken)"/>. Does not lock <see cref="semaphore"/>
/// </summary>
@@ -288,8 +288,8 @@ namespace Tgstation.Server.Host.Components.Watchdog
{
var dmbBackup = await dmbFactory.FromCompileJob(monitorState.ActiveServer.Dmb.CompileJob, cancellationToken).ConfigureAwait(false);
if (dmbBackup == null) //NANI!?
//just give up, if THAT compile job is failing then the ActiveServer is gonna crash soon too or already has
if (dmbBackup == null) //NANI!?
//just give up, if THAT compile job is failing then the ActiveServer is gonna crash soon too or already has
throw new JobException("Creating backup DMB provider failed!");
monitorState.InactiveServer = await sessionControllerFactory.LaunchNew(ActiveLaunchParameters, dmbBackup, null, false, !monitorState.ActiveServer.IsPrimary, false, cancellationToken).ConfigureAwait(false);
@@ -328,7 +328,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
{
monitorState.ActiveServer.ClosePortOnReboot = false;
if (monitorState.InactiveServerHasStagedDmb && !usedLatestDmb)
monitorState.InactiveServerHasStagedDmb = false; //don't try to load it again though
monitorState.InactiveServerHasStagedDmb = false; //don't try to load it again though
}
};
@@ -338,7 +338,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
switch (activationReason)
{
case MonitorActivationReason.ActiveServerCrashed:
if(monitorState.ActiveServer.RebootState == Components.Watchdog.RebootState.Shutdown)
if (monitorState.ActiveServer.RebootState == Components.Watchdog.RebootState.Shutdown)
{
await chat.SendWatchdogMessage(String.Format(CultureInfo.InvariantCulture, "Active server {0}! Exiting due to graceful termination request...", ExitWord(monitorState.ActiveServer)), cancellationToken).ConfigureAwait(false);
monitorState.NextAction = MonitorAction.Exit;
@@ -368,7 +368,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
//what matters here is the RebootState
bool restartOnceSwapped = false;
var rebootState = monitorState.ActiveServer.RebootState;
monitorState.ActiveServer.ResetRebootState(); //the DMAPI has already done this internally
monitorState.ActiveServer.ResetRebootState(); //the DMAPI has already done this internally
switch (rebootState)
{
@@ -411,7 +411,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
}
if (restartOnceSwapped) //for one reason or another
await UpdateAndRestartInactiveServer(true).ConfigureAwait(false); //break because worse case, active server is still booting
await UpdateAndRestartInactiveServer(true).ConfigureAwait(false); //break because worse case, active server is still booting
else
{
monitorState.InactiveServer.ClosePortOnReboot = false;
@@ -432,7 +432,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
break;
case MonitorActivationReason.NewDmbAvailable:
monitorState.InactiveServerHasStagedDmb = true;
await UpdateAndRestartInactiveServer(true).ConfigureAwait(false); //next case does same thing
await UpdateAndRestartInactiveServer(true).ConfigureAwait(false); //next case does same thing
break;
case MonitorActivationReason.ActiveLaunchParametersUpdated:
await UpdateAndRestartInactiveServer(false).ConfigureAwait(false);
@@ -449,18 +449,18 @@ namespace Tgstation.Server.Host.Components.Watchdog
{
logger.LogTrace("Entered MonitorLifetimes");
var iteration = 1;
for(var monitorState = new MonitorState(); monitorState.NextAction != MonitorAction.Exit; ++iteration)
for (var monitorState = new MonitorState(); monitorState.NextAction != MonitorAction.Exit; ++iteration)
{
monitorState.NextAction = MonitorAction.Continue;
logger.LogDebug("Iteration {0} of monitor loop", iteration);
try
{
if(AlphaIsActive)
if (AlphaIsActive)
logger.LogDebug("Alpha is the active server");
else
logger.LogDebug("Bravo is the active server");
if(monitorState.InactiveServerHasStagedDmb)
if (monitorState.InactiveServerHasStagedDmb)
logger.LogDebug("Inactive server has staged .dmb");
if (monitorState.RebootingInactiveServer)
logger.LogDebug("Inactive server is rebooting");
@@ -496,7 +496,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
{
MonitorActivationReason activationReason = default;
//multiple things may have happened, handle them one at a time
for (var moreActivationsToProcess = true; moreActivationsToProcess && monitorState.NextAction == MonitorAction.Continue; )
for (var moreActivationsToProcess = true; moreActivationsToProcess && monitorState.NextAction == MonitorAction.Continue;)
{
if (activeServerLifetime?.IsCompleted == true)
{
@@ -528,7 +528,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
activationReason = MonitorActivationReason.NewDmbAvailable;
newDmbAvailable = null;
}
else if(activeLaunchParametersChanged?.IsCompleted == true)
else if (activeLaunchParametersChanged?.IsCompleted == true)
{
activationReason = MonitorActivationReason.ActiveLaunchParametersUpdated;
activeLaunchParametersChanged = null;
@@ -536,7 +536,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
else
moreActivationsToProcess = false;
if(moreActivationsToProcess)
if (moreActivationsToProcess)
await HandlerMonitorWakeup(activationReason, monitorState, cancellationToken).ConfigureAwait(false);
}
@@ -624,7 +624,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
logger.LogTrace("Aborted due to already running!");
return null;
}
Task chatTask;
//this is necessary, the monitor could be in it's sleep loop trying to restart
if (startMonitor && await StopMonitor().ConfigureAwait(false))
@@ -719,7 +719,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
if (!doesntNeedNewDmb && (alphaServer == null && bravoServer == null))
{
dmbToUse.Dispose(); //guaranteed to not be null here
dmbToUse.Dispose(); //yes, dispose it twice. See the definition of IDmbFactory.LockNextDmb(), we called it with 2 locks
dmbToUse.Dispose(); //yes, dispose it twice. See the definition of IDmbFactory.LockNextDmb(), we called it with 2 locks
}
DisposeAndNullControllers();
throw;
@@ -773,7 +773,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
{
if (!await toReboot.SetRebootState(Components.Watchdog.RebootState.Restart, cancellationToken).ConfigureAwait(false))
logger.LogWarning("Unable to send reboot state change event!");
}
return null;
}
@@ -28,7 +28,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// <param name="copy">The <see cref="WatchdogReattachInformationBase"/> to copy information from</param>
/// <param name="dmbAlpha">The <see cref="IDmbProvider"/> used to build <see cref="Alpha"/></param>
/// <param name="dmbBravo">The <see cref="IDmbProvider"/> used to build <see cref="Bravo"/></param>
public WatchdogReattachInformation(Models.WatchdogReattachInformation copy, IDmbProvider dmbAlpha, IDmbProvider dmbBravo): base(copy)
public WatchdogReattachInformation(Models.WatchdogReattachInformation copy, IDmbProvider dmbAlpha, IDmbProvider dmbBravo) : base(copy)
{
if (copy.Alpha != null)
Alpha = new ReattachInformation(copy.Alpha, dmbAlpha);
@@ -74,7 +74,7 @@ namespace Tgstation.Server.Host.Controllers
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
updatesConfiguration = updatesConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(updatesConfigurationOptions));
}
StatusCodeResult RateLimit(RateLimitExceededException exception)
{
Logger.LogWarning("Exceeded GitHub rate limit!");
@@ -157,13 +157,13 @@ namespace Tgstation.Server.Host.Controllers
return UnprocessableEntity(new ErrorMessage
{
Message = RestartNotSupportedException
}); //unprocessable entity
}); //unprocessable entity
}
catch (InvalidOperationException)
{
return StatusCode((int)HttpStatusCode.ServiceUnavailable); //we were beat to the punch, really shouldn't happen but heat death of the universe and what not
}
return Accepted(); //gtfo of here before all the cancellation tokens fire
return Accepted(); //gtfo of here before all the cancellation tokens fire
}
return StatusCode((int)HttpStatusCode.Gone);
@@ -172,7 +172,8 @@ namespace Tgstation.Server.Host.Controllers
/// <inheritdoc />
[HttpDelete]
[TgsAuthorize(AdministrationRights.RestartHost)]
public Task<IActionResult> Delete() {
public Task<IActionResult> Delete()
{
try
{
return Task.FromResult(serverUpdater.Restart() ? (IActionResult)Ok() : UnprocessableEntity(new ErrorMessage
@@ -81,7 +81,7 @@ namespace Tgstation.Server.Host.Controllers
{
throw new InvalidOperationException("Failed to parse user ID!", e);
}
ApiHeaders apiHeaders;
try
{
@@ -132,7 +132,7 @@ namespace Tgstation.Server.Host.Controllers
Instance = AuthenticationContext?.InstanceUser?.Instance;
this.requireInstance = requireInstance;
}
/// <inheritdoc />
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
@@ -151,7 +151,7 @@ namespace Tgstation.Server.Host.Controllers
{
ApiHeaders = new ApiHeaders(Request.GetTypedHeaders());
if(!ApiHeaders.Compatible())
if (!ApiHeaders.Compatible())
{
await StatusCode((int)HttpStatusCode.UpgradeRequired, new ErrorMessage
{
@@ -162,7 +162,7 @@ namespace Tgstation.Server.Host.Controllers
if (requireInstance)
{
if(!ApiHeaders.InstanceId.HasValue)
if (!ApiHeaders.InstanceId.HasValue)
{
await BadRequest(new ErrorMessage { Message = "Missing Instance header!" }).ExecuteResultAsync(context).ConfigureAwait(false);
return;
@@ -181,7 +181,7 @@ namespace Tgstation.Server.Host.Controllers
return;
}
if(ModelState?.IsValid == false)
if (ModelState?.IsValid == false)
{
var errorMessages = ModelState.SelectMany(x => x.Value.Errors).Select(x => x.ErrorMessage).ToList();
//do some fuckery to remove RequiredAttribute errors
@@ -84,7 +84,7 @@ namespace Tgstation.Server.Host.Controllers
if (!model.Enabled.HasValue)
return BadRequest(new ErrorMessage { Message = "enabled cannot be null!" });
if(!model.ValidateProviderChannelTypes())
if (!model.ValidateProviderChannelTypes())
return BadRequest(new ErrorMessage { Message = "One or more of channels aren't formatted correctly for the given provider!" });
//try to update das db first
@@ -93,7 +93,7 @@ namespace Tgstation.Server.Host.Controllers
Name = model.Name,
ConnectionString = model.ConnectionString,
Enabled = model.Enabled,
Channels = model.Channels?.Select(x => ConvertApiChatChannel(x)).ToList() ?? new List<Models.ChatChannel>(), //important that this isn't null
Channels = model.Channels?.Select(x => ConvertApiChatChannel(x)).ToList() ?? new List<Models.ChatChannel>(), //important that this isn't null
InstanceId = Instance.Id,
Provider = model.Provider,
};
@@ -159,7 +159,7 @@ namespace Tgstation.Server.Host.Controllers
[TgsAuthorize(ChatBotRights.Read)]
public override async Task<IActionResult> GetId(long id, CancellationToken cancellationToken)
{
var query = DatabaseContext.ChatBots.Where(x => x.Id == id).Include(x => x.Channels);
var query = DatabaseContext.ChatBots.Where(x => x.Id == id).Include(x => x.Channels);
var results = await query.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
if (results == default)
@@ -60,7 +60,7 @@ namespace Tgstation.Server.Host.Controllers
return model.LastReadHash == null ? (IActionResult)StatusCode((int)HttpStatusCode.Created, newFile) : Json(newFile);
}
catch(NotImplementedException)
catch (NotImplementedException)
{
return StatusCode((int)HttpStatusCode.NotImplemented);
}
@@ -66,7 +66,7 @@ namespace Tgstation.Server.Host.Controllers
Instance = Instance,
StartedBy = AuthenticationContext.User
};
await jobManager.RegisterOperation(job,
await jobManager.RegisterOperation(job,
async (paramJob, serviceProvider, progressHandler, innerCt) =>
{
var result = await instance.Watchdog.Launch(innerCt).ConfigureAwait(false);
@@ -88,7 +88,7 @@ namespace Tgstation.Server.Host.Controllers
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in the <see cref="IActionResult"/> of the operation</returns>
async Task<IActionResult> ReadImpl(DreamDaemonSettings settings, CancellationToken cancellationToken)
{
{
var instance = instanceManager.GetInstance(Instance);
var dd = instance.Watchdog;
@@ -98,7 +98,7 @@ namespace Tgstation.Server.Host.Controllers
if (settings == null)
settings = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).Select(x => x.DreamDaemonSettings).FirstAsync(cancellationToken).ConfigureAwait(false);
var result = new DreamDaemon();
if(metadata)
if (metadata)
{
var alphaActive = dd.AlphaIsActive;
var llp = dd.LastLaunchParameters;
@@ -179,7 +179,7 @@ namespace Tgstation.Server.Host.Controllers
if (current.SecurityLevel == DreamDaemonSecurity.Ultrasafe)
return BadRequest(new ErrorMessage { Message = "This version of TGS does not support the ultrasafe DreamDaemon configuration!" });
var wd = instanceManager.GetInstance(Instance).Watchdog;
//run these in parallel because they are equally as important
@@ -19,7 +19,7 @@ namespace Tgstation.Server.Host.Controllers
/// Controller for managing the compiler
/// </summary>
[Route(Routes.DreamMaker)]
public sealed class DreamMakerController : ModelController<Api.Models.DreamMaker>
public sealed class DreamMakerController : ModelController<Api.Models.DreamMaker>
{
/// <summary>
/// The <see cref="IJobManager"/> for the <see cref="DreamMakerController"/>
@@ -141,7 +141,8 @@ namespace Tgstation.Server.Host.Controllers
var instanceManager = serviceProvider.GetRequiredService<IInstanceManager>();
var databaseContext = serviceProvider.GetRequiredService<IDatabaseContext>();
var ddSettingsTask = databaseContext.DreamDaemonSettings.Where(x => x.InstanceId == instanceModel.Id).Select(x => new DreamDaemonSettings{
var ddSettingsTask = databaseContext.DreamDaemonSettings.Where(x => x.InstanceId == instanceModel.Id).Select(x => new DreamDaemonSettings
{
StartupTimeout = x.StartupTimeout,
SecurityLevel = x.SecurityLevel
}).FirstAsync(cancellationToken);
@@ -66,7 +66,8 @@ namespace Tgstation.Server.Host.Controllers
/// <returns><see cref="Application.Version"/></returns>
[TgsAuthorize]
[HttpGet]
public JsonResult Home() => Json(new Api.Models.ServerInformation {
public JsonResult Home() => Json(new Api.Models.ServerInformation
{
Version = application.Version,
ApiVersion = ApiHeaders.Version
});
@@ -106,7 +106,7 @@ namespace Tgstation.Server.Host.Controllers
if (String.IsNullOrWhiteSpace(model.Name))
return BadRequest(new ErrorMessage { Message = "name must not be empty!" });
if(model.Path == null)
if (model.Path == null)
return BadRequest(new ErrorMessage { Message = "path must not be empty!" });
NormalizeModelPath(model, out var rawPath);
@@ -175,13 +175,13 @@ namespace Tgstation.Server.Host.Controllers
throw;
}
}
catch(IOException e)
catch (IOException e)
{
return Conflict(new ErrorMessage { Message = e.Message });
}
catch (DbUpdateException e)
{
return Conflict(new ErrorMessage{ Message = e.Message });
return Conflict(new ErrorMessage { Message = e.Message });
}
Logger.LogInformation("{0} {1} instance {2}: {3} ({4})", AuthenticationContext.User.Name, attached ? "attached" : "created", newInstance.Name, newInstance.Id, newInstance.Path);
@@ -327,7 +327,8 @@ namespace Tgstation.Server.Host.Controllers
StartedBy = AuthenticationContext.User
};
await jobManager.RegisterOperation(job, async (paramJob, serviceProvider, progressHandler, ct) => {
await jobManager.RegisterOperation(job, async (paramJob, serviceProvider, progressHandler, ct) =>
{
try
{
await instanceManager.MoveInstance(Instance, rawPath, ct).ConfigureAwait(false);
@@ -84,7 +84,7 @@ namespace Tgstation.Server.Host.Controllers
ActiveTestMerges = new List<RevInfoTestMerge>() //non null vals for api returns
};
lock (databaseContext) //cleaner this way
lock (databaseContext) //cleaner this way
databaseContext.RevisionInformations.Add(revisionInfo);
}
revisionInfo.OriginCommitSha = revisionInfo.OriginCommitSha ?? lastOriginCommitSha ?? repository.Head;
@@ -249,10 +249,10 @@ namespace Tgstation.Server.Host.Controllers
if (model.Origin != null)
return BadRequest(new ErrorMessage { Message = "origin cannot be modified without deleting the repository!" });
if(model.NewTestMerges?.Any(x => !x.Number.HasValue) == true)
if (model.NewTestMerges?.Any(x => !x.Number.HasValue) == true)
return BadRequest(new ErrorMessage { Message = "All new test merges must provide a number!" });
if(model.NewTestMerges?.Any(x => model.NewTestMerges.Any(y => x != y && x.Number == y.Number)) == true)
if (model.NewTestMerges?.Any(x => model.NewTestMerges.Any(y => x != y && x.Number == y.Number)) == true)
return BadRequest(new ErrorMessage { Message = "Cannot test merge the same PR twice in one job!" });
var newTestMerges = model.NewTestMerges != null && model.NewTestMerges.Count > 0;
@@ -374,7 +374,7 @@ namespace Tgstation.Server.Host.Controllers
}
}
}
//checkout/hard reset
if (modelHasShaOrReference)
{
@@ -511,7 +511,7 @@ namespace Tgstation.Server.Host.Controllers
lastRevisionInfo = revInfoWereLookingFor;
}
if(needToApplyRemainingPrs)
if (needToApplyRemainingPrs)
{
var contextUser = new Models.User
{
@@ -576,7 +576,7 @@ namespace Tgstation.Server.Host.Controllers
}
}
}
if (startSha != repo.Head)
{
await repo.Sychronize(currentModel.AccessUser, currentModel.AccessToken, false, ct).ConfigureAwait(false);
@@ -133,7 +133,7 @@ namespace Tgstation.Server.Host.Controllers
var originalUser = passwordEditOnly ? AuthenticationContext.User : await DatabaseContext.Users.Where(x => x.Id == model.Id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
if (originalUser == default)
return StatusCode((int)HttpStatusCode.Gone);
if (passwordEditOnly && (model.Id != originalUser.Id || model.InstanceManagerRights.HasValue || model.AdministrationRights.HasValue || model.Enabled.HasValue || model.SystemIdentifier != null || model.Name != null))
return Forbid();
@@ -143,7 +143,7 @@ namespace Tgstation.Server.Host.Controllers
return BadRequest(new ErrorMessage { Message = "Cannot convert a system user to a password user!" });
cryptographySuite.SetUserPassword(originalUser, model.Password);
}
else if(model.SystemIdentifier != null && model.SystemIdentifier != originalUser.SystemIdentifier)
else if (model.SystemIdentifier != null && model.SystemIdentifier != originalUser.SystemIdentifier)
return BadRequest(new ErrorMessage { Message = "Cannot change a user's system identifier!" });
if (model.Name != null && model.Name.ToUpperInvariant() != originalUser.CanonicalName)
@@ -172,9 +172,15 @@ namespace Tgstation.Server.Host.Controllers
}
/// <inheritdoc />
[TgsAuthorize(AdministrationRights.EditUsers)]
[TgsAuthorize]
public override async Task<IActionResult> GetId(long id, CancellationToken cancellationToken)
{
if (id == AuthenticationContext.User.Id)
return await Read(cancellationToken).ConfigureAwait(false);
if (!((AdministrationRights)AuthenticationContext.GetRight(RightsType.Administration)).HasFlag(AdministrationRights.EditUsers))
return Forbid();
var user = await DatabaseContext.Users.Where(x => x.Id == id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
if (user == default)
return NotFound();
@@ -94,7 +94,7 @@ namespace Tgstation.Server.Host.Core
if (generalConfiguration?.DisableFileLogging != true)
{
var logPath = !String.IsNullOrEmpty(generalConfiguration?.LogFileDirectory) ? generalConfiguration.LogFileDirectory : ioManager.ConcatPath(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), VersionPrefix, "Logs");
var logPath = !String.IsNullOrEmpty(generalConfiguration?.LogFileDirectory) ? generalConfiguration.LogFileDirectory : ioManager.ConcatPath(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), VersionPrefix, "Logs");
services.AddLogging(builder => builder.AddFile(ioManager.ConcatPath(logPath, "tgs-{Date}.log")));
}
@@ -166,7 +166,7 @@ namespace Tgstation.Server.Host.Core
default:
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid {0}!", nameof(DatabaseType)));
}
services.AddScoped<IAuthenticationContextFactory, AuthenticationContextFactory>();
services.AddSingleton<IIdentityCache, IdentityCache>();
@@ -207,7 +207,7 @@ namespace Tgstation.Server.Host.Core
services.AddSingleton<InstanceManager>();
services.AddSingleton<IInstanceManager>(x => x.GetRequiredService<InstanceManager>());
services.AddSingleton<IHostedService>(x => x.GetRequiredService<InstanceManager>());
services.AddSingleton<IJobManager, JobManager>();
services.AddSingleton<IIOManager>(ioManager);
@@ -231,8 +231,8 @@ namespace Tgstation.Server.Host.Core
throw new ArgumentNullException(nameof(logger));
logger.LogInformation(VersionString);
applicationBuilder.UseDeveloperExceptionPage(); //it is not worth it to limit this, you should only ever get it if you're an authorized user
applicationBuilder.UseDeveloperExceptionPage(); //it is not worth it to limit this, you should only ever get it if you're an authorized user
applicationBuilder.UseAsyncInitialization(async cancellationToken =>
{
@@ -10,7 +10,7 @@ namespace Tgstation.Server.Host.Core
/// <summary>
/// Manages the runtime of <see cref="Job"/>s
/// </summary>
public interface IJobManager : IHostedService
public interface IJobManager : IHostedService
{
/// <summary>
/// Get the <see cref="Api.Models.Job.Progress"/> for a job
@@ -34,5 +34,5 @@ namespace Tgstation.Server.Host.Core
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task"/> representing a running operation</returns>
Task CancelJob(Job job, User user, CancellationToken cancellationToken);
}
}
}
@@ -8,8 +8,8 @@ namespace Tgstation.Server.Host.Core
/// <summary>
/// Represents a service that may take an updated <see cref="Host"/> assembly and run it, stopping the current assembly in the process
/// </summary>
public interface IServerControl
{
public interface IServerControl
{
/// <summary>
/// Run a new <see cref="Host"/> assembly and stop the current one. This will likely trigger all active <see cref="CancellationToken"/>s
/// </summary>
@@ -30,5 +30,5 @@ namespace Tgstation.Server.Host.Core
/// </summary>
/// <returns><see langword="true"/> if live restarts are supported, <see langword="false"/> otherwise</returns>
bool Restart();
}
}
}
+2 -2
View File
@@ -136,7 +136,7 @@ namespace Tgstation.Server.Host.Core
databaseContext.Jobs.Add(job);
await databaseContext.Save(cancellationToken).ConfigureAwait(false);
logger.LogDebug("Starting job {0}: {1}...", job.Id, job.Description);
var jobHandler = JobHandler.Create(x => RunJob(job, (jobParam, serviceProvider, ct) =>
var jobHandler = JobHandler.Create(x => RunJob(job, (jobParam, serviceProvider, ct) =>
operation(jobParam, serviceProvider, y =>
{
lock (this)
@@ -192,7 +192,7 @@ namespace Tgstation.Server.Host.Core
throw new ArgumentNullException(nameof(job));
if (user == null)
throw new ArgumentNullException(nameof(user));
CheckGetJob(job).Cancel(); //this will ensure the db update is only done once
CheckGetJob(job).Cancel(); //this will ensure the db update is only done once
using (var scope = serviceProvider.CreateScope())
{
var databaseContext = scope.ServiceProvider.GetRequiredService<IDatabaseContext>();
@@ -84,7 +84,7 @@ namespace Tgstation.Server.Host.IO
async Task CopyThisDirectory()
{
if (!atLeastOneSubDir)
await CreateDirectory(dest, cancellationToken).ConfigureAwait(false); //save on createdir calls
await CreateDirectory(dest, cancellationToken).ConfigureAwait(false); //save on createdir calls
var tasks = new List<Task>();
@@ -108,7 +108,7 @@ namespace Tgstation.Server.Host.IO
throw new ArgumentNullException(nameof(src));
if (dest == null)
throw new ArgumentNullException(nameof(src));
src = ResolvePath(src);
dest = ResolvePath(dest);
foreach (var directoryCopy in CopyDirectoryImpl(src, dest, ignore, cancellationToken))
@@ -292,11 +292,11 @@ namespace Tgstation.Server.Host.IO
wc.DownloadDataAsync(url);
using (cancellationToken.Register(() =>
{
wc.CancelAsync(); //cancelasync alone doesnt do it either! who wrote this!!
wc.CancelAsync(); //cancelasync alone doesnt do it either! who wrote this!!
tcs.SetCanceled();
}))
return await tcs.Task.ConfigureAwait(false);
} //ITS STILL FUCKING DOWNLOADING!!!
} //ITS STILL FUCKING DOWNLOADING!!!
}
/// <inheritdoc />
@@ -20,7 +20,7 @@ namespace Tgstation.Server.Host.IO
/// <param name="_subdirectory">The value of <see cref="subdirectory"/></param>
public ResolvingIOManager(IIOManager parent, string _subdirectory)
{
if(parent == null)
if (parent == null)
throw new ArgumentNullException(nameof(parent));
if (_subdirectory == null)
throw new ArgumentNullException(nameof(_subdirectory));
+6 -6
View File
@@ -5,12 +5,12 @@
/// </summary>
public interface IServerFactory
{
/// <summary>
/// Create a <see cref="IServer"/>
/// </summary>
/// <param name="args">The arguments for the <see cref="IServer"/></param>
/// <summary>
/// Create a <see cref="IServer"/>
/// </summary>
/// <param name="args">The arguments for the <see cref="IServer"/></param>
/// <param name="updatePath">The directory in which to install server updates</param>
/// <returns>A new <see cref="IServer"/></returns>
IServer CreateServer(string[] args, string updatePath);
/// <returns>A new <see cref="IServer"/></returns>
IServer CreateServer(string[] args, string updatePath);
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ namespace Tgstation.Server.Host.Models
{
/// <inheritdoc />
public sealed class ChatBot : Api.Models.Internal.ChatBot
{
{
/// <summary>
/// The <see cref="Api.Models.Instance.Id"/>
/// </summary>
@@ -3,8 +3,8 @@
namespace Tgstation.Server.Host.Models
{
/// <inheritdoc />
public sealed class DreamDaemonSettings : Api.Models.Internal.DreamDaemonSettings
{
public sealed class DreamDaemonSettings : Api.Models.Internal.DreamDaemonSettings
{
/// <summary>
/// The row Id
/// </summary>
@@ -19,7 +19,7 @@ namespace Tgstation.Server.Host.Models
/// The access token used for communication with DD
/// </summary>
public string AccessToken { get; set; }
/// <summary>
/// The <see cref="Api.Models.Instance.Id"/>
/// </summary>
@@ -9,7 +9,7 @@ namespace Tgstation.Server.Host.Models
/// The row Id
/// </summary>
public long Id { get; set; }
/// <summary>
/// The <see cref="Api.Models.Instance.Id"/>
/// </summary>
@@ -6,7 +6,7 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// For initially seeding a database
/// </summary>
interface IDatabaseSeeder
interface IDatabaseSeeder
{
/// <summary>
/// Initially seed a given <paramref name="databaseContext"/>
+3 -3
View File
@@ -12,7 +12,7 @@ namespace Tgstation.Server.Host.Models
/// The <see cref="Models.DreamMakerSettings"/> for the <see cref="Instance"/>
/// </summary>
public DreamMakerSettings DreamMakerSettings { get; set; }
/// <summary>
/// The <see cref="Models.DreamDaemonSettings"/> for the <see cref="Instance"/>
/// </summary>
@@ -42,12 +42,12 @@ namespace Tgstation.Server.Host.Models
/// The <see cref="RevisionInformation"/>s in the <see cref="Instance"/>
/// </summary>
public List<RevisionInformation> RevisionInformations { get; set; }
/// <summary>
/// The <see cref="Jobs"/> in the <see cref="Instance"/>
/// </summary>
public List<Job> Jobs { get; set; }
/// <summary>
/// Convert the <see cref="Instance"/> to it's API form
/// </summary>
@@ -3,8 +3,8 @@
/// <summary>
/// Database representation of <see cref="Components.Watchdog.ReattachInformation"/>
/// </summary>
public sealed class ReattachInformation : ReattachInformationBase
{
public sealed class ReattachInformation : ReattachInformationBase
{
/// <summary>
/// The row Id
/// </summary>
@@ -45,7 +45,7 @@ namespace Tgstation.Server.Host.Models
ActiveTestMerges = ActiveTestMerges.Select(x => x.TestMerge.ToApi()).ToList(),
CompileJobs = CompileJobs.Select(x => new Api.Models.CompileJob
{
Id = x.Id //anti recursion measure
Id = x.Id //anti recursion measure
}).ToList()
};
}
@@ -11,7 +11,7 @@ namespace Tgstation.Server.Host.Models
/// </summary>
[Required]
public User MergedBy { get; set; }
/// <summary>
/// The initial <see cref="RevisionInformation"/> the <see cref="TestMerge"/> was merged with
/// </summary>
@@ -40,7 +40,7 @@ namespace Tgstation.Server.Host.Models
Comment = Comment,
Id = Id,
MergedBy = MergedBy.ToApi(false),
Number =Number,
Number = Number,
PullRequestRevision = PullRequestRevision,
Url = Url
};
+1 -1
View File
@@ -10,7 +10,7 @@ namespace Tgstation.Server.Host
/// <summary>
/// Entrypoint for the <see cref="Process"/>
/// </summary>
static class Program
static class Program
{
/// <summary>
/// The <see cref="IServerFactory"/> to use
@@ -78,7 +78,7 @@ namespace Tgstation.Server.Host.Security
var prop = typeToCheck.GetProperties().Where(x => x.PropertyType == nullableRightsType).First();
var right = prop.GetMethod.Invoke(isInstance ? (object)InstanceUser : User, Array.Empty<object>());
if (right == null)
throw new InvalidOperationException("A user right was null!");
return (ulong)right;
@@ -37,7 +37,7 @@ namespace Tgstation.Server.Host.Security
public AuthenticationContextFactory(ISystemIdentityFactory systemIdentityFactory, IDatabaseContext databaseContext, IIdentityCache identityCache)
{
this.systemIdentityFactory = systemIdentityFactory ?? throw new ArgumentNullException(nameof(systemIdentityFactory));
this.databaseContext = databaseContext?? throw new ArgumentNullException(nameof(databaseContext));
this.databaseContext = databaseContext ?? throw new ArgumentNullException(nameof(databaseContext));
this.identityCache = identityCache ?? throw new ArgumentNullException(nameof(identityCache));
}
@@ -47,7 +47,7 @@ namespace Tgstation.Server.Host.Security
/// <inheritdoc />
public bool CheckUserPassword(User user, string password)
{
switch(passwordHasher.VerifyHashedPassword(user, user.PasswordHash, password))
switch (passwordHasher.VerifyHashedPassword(user, user.PasswordHash, password))
{
case PasswordVerificationResult.Failed:
return false;
@@ -6,7 +6,7 @@ namespace Tgstation.Server.Host.Security
/// <summary>
/// For caching <see cref="ISystemIdentity"/>s
/// </summary>
public interface IIdentityCache
public interface IIdentityCache
{
/// <summary>
/// Keep a <paramref name="user"/>'s <paramref name="systemIdentity"/> alive until an <paramref name="expiry"/> time
@@ -24,7 +24,7 @@ namespace Tgstation.Server.Host.Security
/// Clone the <see cref="ISystemIdentity"/> creating another copy that must have <see cref="IDisposable.Dispose"/> called on it
/// </summary>
/// <returns>A new <see cref="ISystemIdentity"/> mirroring the current one</returns>
ISystemIdentity Clone();
ISystemIdentity Clone();
/// <summary>
/// Runs a given <paramref name="action"/> in the context of the <see cref="ISystemIdentity"/>
@@ -33,5 +33,5 @@ namespace Tgstation.Server.Host.Security
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task"/> representing the running operation</returns>
Task RunImpersonated(Action action, CancellationToken cancellationToken);
}
}
}
@@ -31,7 +31,7 @@ namespace Tgstation.Server.Host.Security
lock (cachedIdentities)
{
if (cachedIdentities.TryGetValue(user.Id, out var identCache))
identCache.Dispose(); //also clears it out
identCache.Dispose(); //also clears it out
identCache = new IdentityCacheObject(systemIdentity.Clone(), () =>
{
lock (cachedIdentities)
@@ -41,7 +41,7 @@ namespace Tgstation.Server.Host.Security
cancellationTokenSource = new CancellationTokenSource();
async Task DisposeOnExipiry(CancellationToken cancellationToken)
async Task DisposeOnExipiry(CancellationToken cancellationToken)
{
using (SystemIdentity)
try
@@ -61,7 +61,7 @@ namespace Tgstation.Server.Host.Security
if (!res)
return null;
using (var handle = new SafeAccessTokenHandle(token)) //checked internally, windows identity always duplicates the handle when constructed with a userToken
using (var handle = new SafeAccessTokenHandle(token)) //checked internally, windows identity always duplicates the handle when constructed with a userToken
return (ISystemIdentity)new WindowsSystemIdentity(new WindowsIdentity(handle.DangerousGetHandle())); //https://github.com/dotnet/corefx/blob/6ed61acebe3214fcf79b4274f2bb9b55c0604a4d/src/System.Security.Principal.Windows/src/System/Security/Principal/WindowsIdentity.cs#L271
}, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current);
}
+5 -4
View File
@@ -35,7 +35,7 @@ namespace Tgstation.Server.Host
/// If a server update has been applied
/// </summary>
bool updated;
/// <summary>
/// The <see cref="cancellationTokenSource"/> for the <see cref="Server"/>
/// </summary>
@@ -60,7 +60,7 @@ namespace Tgstation.Server.Host
public void Dispose() => semaphore.Dispose();
/// <inheritdoc />
[ExcludeFromCodeCoverage]
[ExcludeFromCodeCoverage]
public async Task RunAsync(CancellationToken cancellationToken)
{
using (cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
@@ -121,10 +121,11 @@ namespace Tgstation.Server.Host
throw new ArgumentNullException(nameof(action));
if (cancellationTokenSource == null)
throw new InvalidOperationException("Tried to register an update action on a non-running Server!");
cancellationTokenSource.Token.Register(() => {
cancellationTokenSource.Token.Register(() =>
{
if (RestartRequested)
action();
});
});
}
/// <inheritdoc />
@@ -40,7 +40,7 @@ namespace Tgstation.Server.Host.Service.Tests
var mockLoggerFactory = new LoggerFactory();
mockWatchdogFactory.Setup(x => x.CreateWatchdog(mockLoggerFactory)).Returns(mockWatchdog.Object).Verifiable();
using(var service = new ServerService(mockWatchdogFactory.Object, mockLoggerFactory))
using (var service = new ServerService(mockWatchdogFactory.Object, mockLoggerFactory))
{
onStart.Invoke(service, new object[] { args });
@@ -15,7 +15,7 @@ namespace Tgstation.Server.Tests
public sealed class IntegrationTest
{
readonly IServerClientFactory clientFactory = new ServerClientFactory(new ProductHeaderValue(Assembly.GetExecutingAssembly().GetName().Name, Assembly.GetExecutingAssembly().GetName().Version.ToString()));
[TestMethod]
public async Task FullMonty()
{