using System;
using System.Threading;
namespace Plugin
{
///
/// Result of a query to the engine. Allows to wait until the result is available.
///
/// Type of data inside the result.
public interface IQueryResult
{
///
/// Waits for the result, returns true if the timeout didn't expire.
///
bool Join(out T result, int millisecondsTimeout = QueryResult.DefaultTimeout);
///
/// Triggered when the query is filled.
///
event Action Done;
}
///
/// Result of a query to the engine. Allows to wait until the result is available.
///
/// Type of data inside the result.
public class QueryResult : IQueryResult
{
public const int DefaultTimeout = 2500;
private readonly AbstractPlugin _plugin;
private readonly ManualResetEvent _waitHandle = new ManualResetEvent(false);
private T _content;
public QueryResult(AbstractPlugin plugin)
{
_plugin = plugin;
}
public T Content
{
get { return _content; }
set
{
_content = value;
_waitHandle.Set();
OnDone();
}
}
public bool Join(out T result, int millisecondsTimeout = DefaultTimeout)
{
if (_waitHandle.WaitOne(millisecondsTimeout))
{
result = _content;
return true;
}
result = _content;
_plugin.ReportTimeoutFailure();
return false;
}
///
/// Separated in a backend and the interface so we can trigger the event right away if already filled.
///
private event Action DoneBackend;
///
/// Triggered when the query is filled.
///
public event Action Done
{
add
{
DoneBackend += value;
// When already set, we trigger the event right now.
if (_waitHandle.WaitOne(0))
{
OnDone();
}
}
remove { DoneBackend -= value; }
}
protected virtual void OnDone()
{
var done = DoneBackend;
if (done != null)
{
done(Content);
}
}
}
}