// 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;
}
}
}