Fix a ton of shit

This commit is contained in:
Jordan Brown
2018-07-30 12:55:46 -04:00
parent 331eb88fc4
commit bd35e807f2
8 changed files with 433 additions and 38 deletions
@@ -33,7 +33,8 @@ namespace Tgstation.Server.Api.Models.Internal
/// When the <see cref="Job"/> was started
/// </summary>
[Permissions(DenyWrite = true)]
public DateTimeOffset StartedAt { get; set; }
[Required]
public DateTimeOffset? StartedAt { get; set; }
/// <summary>
/// When the <see cref="Job"/> stopped
@@ -45,7 +46,8 @@ namespace Tgstation.Server.Api.Models.Internal
/// If the <see cref="Job"/> was cancelled
/// </summary>
[Permissions(DenyWrite = true)]
public bool Cancelled { get; set; }
[Required]
public bool? Cancelled { get; set; }
/// <summary>
/// The <see cref="RightsType"/> of <see cref="CancelRight"/> if it can be cancelled
@@ -5,6 +5,7 @@ using System.Globalization;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.IO;
namespace Tgstation.Server.Host.Components.Byond
@@ -12,7 +13,7 @@ namespace Tgstation.Server.Host.Components.Byond
/// <summary>
/// <see cref="IByondInstaller"/> for windows systems
/// </summary>
sealed class WindowsByondInstaller : IByondInstaller
sealed class WindowsByondInstaller : IByondInstaller, IDisposable
{
/// <summary>
/// The URL format string for getting BYOND windows version {0}.{1} zipfile
@@ -51,6 +52,11 @@ namespace Tgstation.Server.Host.Components.Byond
/// </summary>
readonly ILogger<WindowsByondInstaller> logger;
/// <summary>
/// The <see cref="SemaphoreSlim"/> for the <see cref="WindowsByondInstaller"/>
/// </summary>
readonly SemaphoreSlim semaphore;
/// <summary>
/// If DirectX was installed
/// </summary>
@@ -66,9 +72,13 @@ namespace Tgstation.Server.Host.Components.Byond
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
semaphore = new SemaphoreSlim(1);
installedDirectX = false;
}
/// <inheritdoc />
public void Dispose() => semaphore.Dispose();
/// <inheritdoc />
public async Task CleanCache(CancellationToken cancellationToken)
{
@@ -103,8 +113,8 @@ namespace Tgstation.Server.Host.Components.Byond
var setNoPromptTrustedModeTask = SetNoPromptTrusted();
//after this version lummox made DD depend of directx lol
if (version.Major >= 512 && version.Minor >= 1427 && Monitor.TryEnter(this))
try
if (version.Major >= 512 && version.Minor >= 1427 && !installedDirectX)
using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
{
if (!installedDirectX)
//always install it, it's pretty fast and will do better redundancy checking than us
@@ -143,10 +153,6 @@ namespace Tgstation.Server.Host.Components.Byond
installedDirectX = true;
}
}
finally
{
Monitor.Exit(this);
}
await setNoPromptTrustedModeTask.ConfigureAwait(false);
}
@@ -107,7 +107,7 @@ namespace Tgstation.Server.Host.Components.Compiler
{
if (job == null)
throw new ArgumentNullException(nameof(job));
if (job.DMApiValidated != true || job.Job.Cancelled || job.Job.ExceptionDetails != null || job.Job.StoppedAt == null)
if (job.DMApiValidated != true || job.Job.Cancelled.Value || job.Job.ExceptionDetails != null || job.Job.StoppedAt == null)
throw new InvalidOperationException("Cannot load incomplete compile job!");
if (setAsStagedInDb)
await databaseContextFactory.UseContext(async db =>
@@ -3,7 +3,6 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Rights;
@@ -73,25 +72,6 @@ namespace Tgstation.Server.Host.Controllers
return Json(job);
}
/// <inheritdoc />
[TgsAuthorize(DreamMakerRights.CancelCompile)]
public override async Task<IActionResult> Delete(long id, CancellationToken cancellationToken)
{
//alias for cancelling the latest job
var job = await DatabaseContext.CompileJobs.OrderByDescending(x => x.Job.StartedAt).Select(x => new Job { Id = x.Job.Id, StoppedAt = x.Job.StoppedAt }).FirstAsync(cancellationToken).ConfigureAwait(false);
if (job.StoppedAt != null)
return StatusCode((int)HttpStatusCode.Gone);
try
{
await jobManager.CancelJob(job, AuthenticationContext.User, cancellationToken).ConfigureAwait(false);
}
catch (InvalidOperationException) //job already stopped
{
return StatusCode((int)HttpStatusCode.Gone);
}
return Ok();
}
/// <inheritdoc />
[TgsAuthorize(DreamMakerRights.SetDme)]
public override async Task<IActionResult> Update([FromBody] Api.Models.DreamMaker model, CancellationToken cancellationToken)
@@ -68,7 +68,7 @@ namespace Tgstation.Server.Host.Controllers
/// <param name="id">The ID of the model to delete</param>
/// <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>
[HttpDelete]
[HttpDelete("{id}")]
public virtual Task<IActionResult> Delete(long id, CancellationToken cancellationToken) => Task.FromResult((IActionResult)NotFound());
/// <summary>
+11 -5
View File
@@ -10,7 +10,7 @@ using Tgstation.Server.Host.Models;
namespace Tgstation.Server.Host.Core
{
/// <inheritdoc />
sealed class JobManager : IHostedService, IJobManager
sealed class JobManager : IHostedService, IJobManager, IDisposable
{
/// <summary>
/// The <see cref="IServiceProvider"/> for the <see cref="JobManager"/>
@@ -31,6 +31,13 @@ namespace Tgstation.Server.Host.Core
jobs = new Dictionary<long, JobHandler>();
}
/// <inheritdoc />
public void Dispose()
{
foreach (var job in jobs)
job.Value.Dispose();
}
/// <summary>
/// Gets the <see cref="JobHandler"/> for a given <paramref name="job"/> if it exists
/// </summary>
@@ -104,6 +111,7 @@ namespace Tgstation.Server.Host.Core
{
var databaseContext = scope.ServiceProvider.GetRequiredService<IDatabaseContext>();
job.StartedAt = DateTimeOffset.Now;
job.Cancelled = false;
job.Instance = new Instance
{
Id = job.Instance.Id
@@ -134,7 +142,7 @@ namespace Tgstation.Server.Host.Core
await databaseContext.Initialize(cancellationToken).ConfigureAwait(false);
//mark all jobs as cancelled
var enumerator = await databaseContext.Jobs.Where(y => !y.Cancelled && y.StoppedAt == null).Select(y => y.Id).ToAsyncEnumerable().ToList(cancellationToken).ConfigureAwait(false);
var enumerator = await databaseContext.Jobs.Where(y => !y.Cancelled.Value && !y.StoppedAt.HasValue).Select(y => y.Id).ToAsyncEnumerable().ToList(cancellationToken).ConfigureAwait(false);
foreach(var I in enumerator)
{
var job = new Job { Id = I };
@@ -154,9 +162,6 @@ namespace Tgstation.Server.Host.Core
return x.Value.Wait(cancellationToken);
});
await Task.WhenAll(joinTasks).ConfigureAwait(false);
foreach (var job in jobs)
job.Value.Dispose();
jobs.Clear();
}
/// <inheritdoc />
@@ -175,6 +180,7 @@ namespace Tgstation.Server.Host.Core
user = new User { Id = user.Id };
databaseContext.Users.Attach(user);
job.CancelledBy = user;
//let either startup or cancellation set job.cancelled
await databaseContext.Save(cancellationToken).ConfigureAwait(false);
}
}
@@ -265,9 +265,27 @@ namespace Tgstation.Server.Host.IO
/// <inheritdoc />
public async Task<byte[]> DownloadFile(Uri url, CancellationToken cancellationToken)
{
//DownloadDataTaskAsync can't be cancelled and is shittily written, don't use it
using (var wc = new WebClient())
using (cancellationToken.Register(() => wc.CancelAsync()))
return await wc.DownloadDataTaskAsync(url).ConfigureAwait(false);
{
var tcs = new TaskCompletionSource<byte[]>();
wc.DownloadDataCompleted += (a, b) =>
{
if (b.Error != null)
tcs.TrySetException(b.Error);
else if (b.Cancelled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(b.Result);
};
wc.DownloadDataAsync(url);
using (cancellationToken.Register(() =>
{
wc.CancelAsync(); //cancelasync alone doesnt do it either! who wrote this!!
tcs.SetCanceled();
}))
return await tcs.Task.ConfigureAwait(false);
} //ITS STILL FUCKING DOWNLOADING!!!
}
/// <inheritdoc />
+383
View File
@@ -842,6 +842,49 @@
},
"response": []
},
{
"name": "Set ID 1 to only #botbus",
"request": {
"method": "POST",
"header": [
{
"key": "Accept",
"value": "application/json"
},
{
"key": "User-Agent",
"value": "Postman/1.0"
},
{
"key": "User-Agent",
"value": "Tgstation.Server.Api/4.0.0.0"
},
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "InstanceId",
"value": "1"
}
],
"body": {
"mode": "raw",
"raw": "{\n\t\"id\": 1,\n\t\"channels\": [\n\t\t{\n\t\t\t\"ircChannel\": \"#botbus\",\n\t\t\t\"isAdminChannel\": true,\n\t\t\t\"isWatchdogChannel\": true\n\t\t}\n\t\t]\n}"
},
"url": {
"raw": "localhost:5000/Chat",
"host": [
"localhost"
],
"port": "5000",
"path": [
"Chat"
]
}
},
"response": []
},
{
"name": "Create r4407 on Disord",
"request": {
@@ -1199,6 +1242,167 @@
],
"_postman_isSubFolder": true
},
{
"name": "Jobs",
"description": "",
"item": [
{
"name": "List Ids",
"request": {
"method": "GET",
"header": [
{
"key": "Accept",
"value": "application/json"
},
{
"key": "User-Agent",
"value": "Postman/1.0"
},
{
"key": "User-Agent",
"value": "Tgstation.Server.Api/4.0.0.0"
},
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "InstanceId",
"value": "1"
}
],
"body": {
"mode": "raw",
"raw": "{\n\t\"userId\": 1,\n\t\"byondRights\": -1,\n\t\"dreamDaemonRights\": -1,\n\t\"dreamMakerRights\": -1,\n\t\"repositoryRights\": -1,\n\t\"chatSettingsRights\": -1,\n\t\"configurationRights\": -1\n}"
},
"url": {
"raw": "localhost:5000/Job/List",
"host": [
"localhost"
],
"port": "5000",
"path": [
"Job",
"List"
]
}
},
"response": []
},
{
"name": "Get ID",
"request": {
"method": "GET",
"header": [
{
"key": "Accept",
"value": "application/json"
},
{
"key": "User-Agent",
"value": "Postman/1.0"
},
{
"key": "User-Agent",
"value": "Tgstation.Server.Api/4.0.0.0"
},
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "InstanceId",
"value": "1"
}
],
"body": {
"mode": "raw",
"raw": "{\n\t\"userId\": 1,\n\t\"byondRights\": -1,\n\t\"dreamDaemonRights\": -1,\n\t\"dreamMakerRights\": -1,\n\t\"repositoryRights\": -1,\n\t\"chatSettingsRights\": -1,\n\t\"configurationRights\": -1\n}"
},
"url": {
"raw": "localhost:5000/Job/10",
"host": [
"localhost"
],
"port": "5000",
"path": [
"Job",
"10"
]
}
},
"response": []
},
{
"name": "Cancel ID",
"request": {
"method": "DELETE",
"header": [
{
"key": "Accept",
"value": "application/json"
},
{
"key": "User-Agent",
"value": "Postman/1.0"
},
{
"key": "User-Agent",
"value": "Tgstation.Server.Api/4.0.0.0"
},
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "InstanceId",
"value": "1"
}
],
"body": {
"mode": "raw",
"raw": ""
},
"url": {
"raw": "localhost:5000/Job/11",
"host": [
"localhost"
],
"port": "5000",
"path": [
"Job",
"11"
]
}
},
"response": []
}
],
"event": [
{
"listen": "prerequest",
"script": {
"id": "a3f3a2f7-5700-48a9-88bf-d18ac2a1855c",
"type": "text/javascript",
"exec": [
""
]
}
},
{
"listen": "test",
"script": {
"id": "787a5a17-ad9c-4772-9052-85d81e87d4a9",
"type": "text/javascript",
"exec": [
""
]
}
}
],
"_postman_isSubFolder": true
},
{
"name": "Online Instance ID 1",
"request": {
@@ -1397,6 +1601,185 @@
}
]
},
{
"name": "Byond",
"description": "",
"item": [
{
"name": "List installed versions",
"request": {
"method": "GET",
"header": [
{
"key": "Accept",
"value": "application/json"
},
{
"key": "User-Agent",
"value": "Postman/1.0"
},
{
"key": "User-Agent",
"value": "Tgstation.Server.Api/4.0.0.0"
},
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "InstanceId",
"value": "1"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"id\": 1,\n \"online\": false\n}"
},
"url": {
"raw": "localhost:5000/Byond/List",
"host": [
"localhost"
],
"port": "5000",
"path": [
"Byond",
"List"
]
}
},
"response": []
},
{
"name": "Read active version",
"request": {
"method": "GET",
"header": [
{
"key": "Accept",
"value": "application/json"
},
{
"key": "User-Agent",
"value": "Postman/1.0"
},
{
"key": "User-Agent",
"value": "Tgstation.Server.Api/4.0.0.0"
},
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "InstanceId",
"value": "1"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"id\": 1,\n \"online\": false\n}"
},
"url": {
"raw": "localhost:5000/Byond",
"host": [
"localhost"
],
"port": "5000",
"path": [
"Byond"
]
}
},
"response": []
},
{
"name": "Set 511.1385 active",
"request": {
"method": "POST",
"header": [
{
"key": "Accept",
"value": "application/json"
},
{
"key": "User-Agent",
"value": "Postman/1.0"
},
{
"key": "User-Agent",
"value": "Tgstation.Server.Api/4.0.0.0"
},
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "InstanceId",
"value": "1"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"version\": {\n \t\"major\": 511,\n \t\"minor\": 1385\n }\n}"
},
"url": {
"raw": "localhost:5000/Byond",
"host": [
"localhost"
],
"port": "5000",
"path": [
"Byond"
]
}
},
"response": []
},
{
"name": "Set 512.1441 active",
"request": {
"method": "POST",
"header": [
{
"key": "Accept",
"value": "application/json"
},
{
"key": "User-Agent",
"value": "Postman/1.0"
},
{
"key": "User-Agent",
"value": "Tgstation.Server.Api/4.0.0.0"
},
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "InstanceId",
"value": "1"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"version\": {\n \t\"major\": 512,\n \t\"minor\": 1441\n }\n}"
},
"url": {
"raw": "localhost:5000/Byond",
"host": [
"localhost"
],
"port": "5000",
"path": [
"Byond"
]
}
},
"response": []
}
]
},
{
"name": "Login Admin Default",
"request": {