// Copyright Epic Games, Inc. All Rights Reserved. using Google.Protobuf; using Google.Protobuf.Reflection; using Google.Protobuf.WellKnownTypes; using HordeServer.Models; using HordeServer.Services; using MongoDB.Bson; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace HordeServer.Tasks { /// /// Information about a new task /// public class NewLeaseInfo { /// /// Lease to execute the task /// public AgentLease Lease { get; } /// /// Callback for connection to the agent being lost /// public Action? OnConnectionLost { get; } /// /// Constructor /// /// /// public NewLeaseInfo(AgentLease Lease, Action? OnConnectionLost = null) { this.Lease = Lease; this.OnConnectionLost = OnConnectionLost; } } /// /// Interface for a an object that waits for a task /// public interface ITaskListener : IAsyncDisposable { /// /// Task returning a lease for the agent. If a null lease is returned, subsequent task sources will not be checked for leases. /// Task LeaseTask { get; } /// /// Whether this lease has been accepted. An lease which has not been accepted will be returned to the pool when the subscription is disposed. /// bool Accepted { get; set; } } class TaskSubscription : ITaskListener { public Task LeaseTask { get; } public bool Accepted { get; set; } public TaskSubscription(Task LeaseTask) { this.LeaseTask = LeaseTask; } public static TaskSubscription FromResult(AgentLease? Lease) { if (Lease == null) { return new TaskSubscription(Task.FromResult(null)); } else { return new TaskSubscription(Task.FromResult(new NewLeaseInfo(Lease))); } } public ValueTask DisposeAsync() { return default; } } /// /// Handler for a certain lease type /// public interface ITaskSource { /// /// Descriptor for this lease type /// MessageDescriptor Descriptor { get; } /// /// Subscribes an agent to execute leases for this source. The lifetime of the returned subscription object indicates the time that the agent is volunteering for work. /// /// The agent state /// The subscription object Task SubscribeAsync(IAgent Agent); /// /// Force a lease as complete /// /// The agent that was allocated to the lease /// The lease id /// The lease payload /// Async task Task AbortTaskAsync(IAgent Agent, ObjectId LeaseId, Any Payload); } /// /// Strongly typed base class for implementation of ITaskHandler /// /// Type of task message public abstract class TaskSourceBase : ITaskSource where T : IMessage, new() { /// public MessageDescriptor Descriptor { get; } = new T().Descriptor; /// public abstract Task SubscribeAsync(IAgent Agent); /// public Task AbortTaskAsync(IAgent Agent, ObjectId LeaseId, Any Payload) { return AbortTaskAsync(Agent, LeaseId, Payload.Unpack()); } /// /// Cancels the given task /// /// Agent executing the task /// The lease id /// The task type /// Async task protected virtual Task AbortTaskAsync(IAgent Agent, ObjectId LeaseId, T Payload) { return Task.CompletedTask; } } }