mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-30 16:39:21 +01:00
Merge pull request #578 from Cyberboss/YeahButItsNotRunning
Formatting Cleanup
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user