You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Framework/Connected.Collections/Concurrent/QueuedDispatcher.cs

100 lines
2.1 KiB

using System.Collections.Concurrent;
using Microsoft.Extensions.DependencyInjection;
namespace Connected.Collections.Concurrent;
internal sealed class QueuedDispatcher<TArgs, TJob> : IDispatcher<TArgs, TJob>
where TJob : IDispatcherJob<TArgs>
{
public event EventHandler? Completed;
public QueuedDispatcher(IDispatcher<TArgs, TJob> dispatcher, string queueName)
{
Dispatcher = dispatcher;
Queue = new();
QueueName = queueName;
/*
* Dispatcher jobs should be transient so it's safe to request a service from the root collection.
*/
if (CollectionsStartup.Application?.Services.GetService<DispatcherJob<TArgs>>() is not DispatcherJob<TArgs> job)
throw new SysException(this, $"{SR.ErrCreateService} ({typeof(DispatcherJob<TArgs>).Name})");
job.Completed += OnCompleted;
Job = job;
}
public CancellationToken CancellationToken => Dispatcher.CancellationToken;
public bool IsDisposed { get; private set; }
public DispatcherProcessBehavior Behavior => DispatcherProcessBehavior.Queued;
public string QueueName { get; }
private DispatcherJob<TArgs> Job { get; set; }
private IDispatcher<TArgs, TJob> Dispatcher { get; set; }
public int Count => Queue.Count;
private ConcurrentQueue<TArgs> Queue { get; set; }
public void Cancel()
{
}
public bool Dequeue(out TArgs? item)
{
return Queue.TryDequeue(out item);
}
public bool Enqueue(TArgs item)
{
if (IsDisposed)
return false;
Queue.Enqueue(item);
if (!Job.IsRunning)
Job.Run(Queue, CancellationToken);
return true;
}
private void OnCompleted(object? sender, EventArgs e)
{
if (sender is not DispatcherJob<TArgs> job)
return;
if (!Queue.IsEmpty)
{
job.Run(Queue, CancellationToken);
return;
}
Completed?.Invoke(this, EventArgs.Empty);
}
public bool Enqueue(string queue, TArgs args)
{
return Dispatcher.Enqueue(queue, args);
}
private void Dispose(bool disposing)
{
if (!IsDisposed)
{
if (disposing)
{
if (Job is not null)
{
Job.Dispose();
Job = null;
}
}
IsDisposed = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}