mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-26 22:48:20 +01:00
That's the jobs controller
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user