That's the jobs controller

This commit is contained in:
Cyberboss
2018-05-07 11:50:00 -04:00
parent 18304741c5
commit 64dc20e556
5 changed files with 114 additions and 35 deletions
@@ -0,0 +1,70 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Models;
using Tgstation.Server.Host.Security;
namespace Tgstation.Server.Host.Controllers
{
/// <summary>
/// <see cref="ModelController{TModel}"/> for <see cref="Api.Models.Job"/>s
/// </summary>
[Route("/Job")]
public sealed class JobController : ModelController<Api.Models.Job>
{
/// <summary>
/// The <see cref="IJobManager"/> for the <see cref="JobController"/>
/// </summary>
readonly IJobManager jobManager;
/// <summary>
/// Construct a <see cref="HomeController"/>
/// </summary>
/// <param name="databaseContext">The <see cref="IDatabaseContext"/> for the <see cref="ApiController"/></param>
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
/// <param name="jobManager">The value of <see cref="jobManager"/></param>
public JobController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IJobManager jobManager) : base(databaseContext, authenticationContextFactory)
{
this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager));
}
/// <inheritdoc />
[TgsAuthorize]
public override async Task<IActionResult> List(CancellationToken cancellationToken)
{
IQueryable<Job> query = DatabaseContext.Jobs;
if (Instance != null)
{
if (!AuthenticationContext.InstanceUser.AnyRights)
return Forbid();
query = query.Where(x => x.Instance.Id == Instance.Id);
}
else
query = query.Where(x => x.Instance == null);
var jobs = await query.Where(x => x.StoppedAt == null).ToListAsync(cancellationToken).ConfigureAwait(false);
return Json(jobs.Select(x => x.ToApi()));
}
/// <inheritdoc />
[TgsAuthorize]
public override async Task<IActionResult> Delete([FromBody] Api.Models.Job model, CancellationToken cancellationToken)
{
//don't care if an instance post or not at this point
var job = await DatabaseContext.Jobs.Where(x => x.Id == model.Id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
if (job == default(Job))
return NotFound();
if(job.StoppedAt != null)
return StatusCode(HttpStatusCode.Gone);
await jobManager.CancelJob(job, AuthenticationContext.User, cancellationToken).ConfigureAwait(false);
return Ok();
}
}
}
@@ -20,14 +20,6 @@ namespace Tgstation.Server.Host.Core
/// <returns>A <see cref="Task"/> representing a running operation</returns>
Task RegisterOperation(Job job, Func<Job, IServiceProvider, CancellationToken, Task> operation, CancellationToken cancellationToken);
/// <summary>
/// Wait for a given <paramref name="job"/> to complete
/// </summary>
/// <param name="job">The <see cref="Job"/> to wait for</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task"/> representing a running operation</returns>
Task WaitForJob(Job job, CancellationToken cancellationToken);
/// <summary>
/// Cancels a give <paramref name="job"/>
/// </summary>
+29 -27
View File
@@ -55,33 +55,45 @@ namespace Tgstation.Server.Host.Core
/// <returns>A <see cref="Task"/> representing the running operation</returns>
async Task RunJob(Job job, Func<Job, IServiceProvider, CancellationToken, Task> operation, CancellationToken cancellationToken)
{
using (var scope = serviceProvider.CreateScope())
try
{
IDatabaseContext databaseContext = null;
try
using (var scope = serviceProvider.CreateScope())
{
var oldJob = job;
job = new Job { Id = oldJob.Id };
IDatabaseContext databaseContext = null;
try
{
await operation(job, scope.ServiceProvider, cancellationToken).ConfigureAwait(false);
var oldJob = job;
job = new Job { Id = oldJob.Id };
try
{
await operation(job, scope.ServiceProvider, cancellationToken).ConfigureAwait(false);
}
finally
{
databaseContext = scope.ServiceProvider.GetRequiredService<IDatabaseContext>();
databaseContext.Jobs.Attach(job);
}
}
finally
catch (OperationCanceledException)
{
databaseContext = scope.ServiceProvider.GetRequiredService<IDatabaseContext>();
databaseContext.Jobs.Attach(job);
job.Cancelled = true;
}
catch (Exception e)
{
job.ExceptionDetails = e.ToString();
}
job.StoppedAt = DateTimeOffset.Now;
await databaseContext.Save(default).ConfigureAwait(false);
}
catch (OperationCanceledException)
}
finally
{
lock (this)
{
job.Cancelled = true;
var handler = jobs[job.Id];
jobs.Remove(job.Id);
handler.Dispose();
}
catch (Exception e)
{
job.ExceptionDetails = e.ToString();
}
job.StoppedAt = DateTimeOffset.Now;
await databaseContext.Save(default).ConfigureAwait(false);
}
}
@@ -134,16 +146,6 @@ namespace Tgstation.Server.Host.Core
jobs.Clear();
}
/// <inheritdoc />
public async Task WaitForJob(Job job, CancellationToken cancellationToken)
{
var handler = CheckGetJob(job);
await handler.Wait(cancellationToken).ConfigureAwait(false);
lock (this)
jobs.Remove(job.Id);
handler.Dispose();
}
/// <inheritdoc />
public async Task CancelJob(Job job, User user, CancellationToken cancellationToken)
{
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using Tgstation.Server.Api.Rights;
namespace Tgstation.Server.Host.Models
{
@@ -15,5 +16,14 @@ namespace Tgstation.Server.Host.Models
/// </summary>
[Required]
public Instance Instance { get; set; }
/// <summary>
/// If the <see cref="InstanceUser"/> has any instance rights
/// </summary>
public bool AnyRights => ByondRights != ByondRights.None ||
ChatSettingsRights != ChatSettingsRights.None ||
ConfigurationRights != ConfigurationRights.None ||
DreamDaemonRights != DreamDaemonRights.None ||
DreamMakerRights != DreamMakerRights.None;
}
}
+5
View File
@@ -16,6 +16,11 @@ namespace Tgstation.Server.Host.Models
/// </summary>
public User CancelledBy { get; set; }
/// <summary>
/// The <see cref="Instance"/> the job belongs to if any
/// </summary>
public Instance Instance { get; set; }
/// <inheritdoc />
public Api.Models.Job ToApi() => new Api.Models.Job
{