This repository has been archived by the owner on Jan 29, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Started adding an async message response helper to tackle #56
- Loading branch information
Showing
6 changed files
with
264 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
164 changes: 164 additions & 0 deletions
164
XMPP_API/Classes/Network/XML/Messages/Helper/AsyncMessageResponseHelper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace XMPP_API.Classes.Network.XML.Messages.Helper | ||
{ | ||
public class AsyncMessageResponseHelper<T> : IDisposable where T : AbstractAddressableMessage | ||
{ | ||
//--------------------------------------------------------Attributes:-----------------------------------------------------------------\\ | ||
#region --Attributes-- | ||
private readonly Predicate<T> IS_VALID_ANSWER; | ||
|
||
private readonly IMessageSender MESSAGE_SENDER; | ||
private readonly bool CACHE_IF_NOT_CONNECTED; | ||
private readonly SemaphoreSlim METHOD_SEMA = new SemaphoreSlim(1, 1); | ||
|
||
/// <summary> | ||
/// Default timeout for requests is 5 seconds. | ||
/// </summary> | ||
public readonly TimeSpan TIMEOUT = TimeSpan.FromSeconds(5.0); | ||
private Task timeoutTask; | ||
private TaskCompletionSource<MessageResponseHelperResult<T>> completionSource; | ||
|
||
public bool matchId = true; | ||
public string sendId; | ||
private bool done; | ||
|
||
private bool disposed; | ||
|
||
#endregion | ||
//--------------------------------------------------------Constructor:----------------------------------------------------------------\\ | ||
#region --Constructors-- | ||
public AsyncMessageResponseHelper(IMessageSender messageSender, Predicate<T> isValidAnswer) : this(messageSender, isValidAnswer, false) { } | ||
|
||
public AsyncMessageResponseHelper(IMessageSender messageSender, Predicate<T> isValidAnswer, bool cacheIfNotConnected) | ||
{ | ||
this.MESSAGE_SENDER = messageSender; | ||
this.IS_VALID_ANSWER = isValidAnswer; | ||
this.CACHE_IF_NOT_CONNECTED = cacheIfNotConnected; | ||
} | ||
|
||
#endregion | ||
//--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\ | ||
#region --Set-, Get- Methods-- | ||
|
||
|
||
#endregion | ||
//--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\ | ||
#region --Misc Methods (Public)-- | ||
public void Dispose() | ||
{ | ||
stop(); | ||
disposed = true; | ||
} | ||
|
||
public async Task<MessageResponseHelperResult<T>> startAsync(AbstractMessage msg) | ||
{ | ||
done = false; | ||
MESSAGE_SENDER.NewValidMessage += MESSAGE_SENDER_NewValidMessage; | ||
|
||
bool success = await MESSAGE_SENDER.sendAsync(msg, CACHE_IF_NOT_CONNECTED); | ||
if (!success) | ||
{ | ||
if (CACHE_IF_NOT_CONNECTED) | ||
{ | ||
return new MessageResponseHelperResult<T>(MessageResponseHelperResultState.WILL_SEND_LATER); | ||
} | ||
return new MessageResponseHelperResult<T>(MessageResponseHelperResultState.SEND_FAILED); | ||
} | ||
|
||
if (disposed) | ||
{ | ||
return new MessageResponseHelperResult<T>(MessageResponseHelperResultState.DISPOSED); | ||
} | ||
|
||
return await waitForCompletionAsync(); | ||
} | ||
|
||
public void stop() | ||
{ | ||
if (!disposed) | ||
{ | ||
done = true; | ||
if (!(completionSource is null) && !completionSource.Task.IsCanceled && !completionSource.Task.IsCompleted && !completionSource.Task.IsFaulted) | ||
{ | ||
completionSource.SetResult(new MessageResponseHelperResult<T>(MessageResponseHelperResultState.TIMEOUT)); | ||
} | ||
|
||
if (!(MESSAGE_SENDER is null)) | ||
{ | ||
MESSAGE_SENDER.NewValidMessage -= MESSAGE_SENDER_NewValidMessage; | ||
} | ||
} | ||
} | ||
|
||
#endregion | ||
|
||
#region --Misc Methods (Private)-- | ||
private async Task<MessageResponseHelperResult<T>> waitForCompletionAsync() | ||
{ | ||
// Create all tasks: | ||
completionSource = new TaskCompletionSource<MessageResponseHelperResult<T>>(); | ||
timeoutTask = Task.Delay(TIMEOUT); | ||
|
||
// Wait for completion: | ||
Task resultTask = await Task.WhenAny(new Task[] { completionSource.Task, timeoutTask }); | ||
MessageResponseHelperResult<T> result = null; | ||
|
||
// Evaluate and return result: | ||
if (resultTask == completionSource.Task) | ||
{ | ||
if (completionSource.Task.IsCompleted) | ||
{ | ||
result = completionSource.Task.Result; | ||
} | ||
else | ||
{ | ||
result = new MessageResponseHelperResult<T>(MessageResponseHelperResultState.ERROR); | ||
} | ||
} | ||
else | ||
{ | ||
result = new MessageResponseHelperResult<T>(MessageResponseHelperResultState.TIMEOUT); | ||
} | ||
|
||
stop(); | ||
return result; | ||
} | ||
|
||
#endregion | ||
|
||
#region --Misc Methods (Protected)-- | ||
|
||
|
||
#endregion | ||
//--------------------------------------------------------Events:---------------------------------------------------------------------\\ | ||
#region --Events-- | ||
private async void MESSAGE_SENDER_NewValidMessage(IMessageSender sender, Events.NewValidMessageEventArgs args) | ||
{ | ||
await METHOD_SEMA.WaitAsync(); | ||
if (disposed || done) | ||
{ | ||
return; | ||
} | ||
|
||
if (args.MESSAGE is T msg) | ||
{ | ||
if (matchId && !string.Equals(sendId, msg.ID)) | ||
{ | ||
return; | ||
} | ||
|
||
if (IS_VALID_ANSWER(msg)) | ||
{ | ||
completionSource.TrySetResult(new MessageResponseHelperResult<T>(MessageResponseHelperResultState.SUCCESS, msg)); | ||
done = true; | ||
} | ||
} | ||
METHOD_SEMA.Release(); | ||
} | ||
|
||
#endregion | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
XMPP_API/Classes/Network/XML/Messages/Helper/MessageResponseHelperResult.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
namespace XMPP_API.Classes.Network.XML.Messages.Helper | ||
{ | ||
public class MessageResponseHelperResult<T> where T : AbstractAddressableMessage | ||
{ | ||
//--------------------------------------------------------Attributes:-----------------------------------------------------------------\\ | ||
#region --Attributes-- | ||
public readonly MessageResponseHelperResultState STATE; | ||
public readonly T RESULT; | ||
|
||
#endregion | ||
//--------------------------------------------------------Constructor:----------------------------------------------------------------\\ | ||
#region --Constructors-- | ||
internal MessageResponseHelperResult(MessageResponseHelperResultState state) : this(state, null) { } | ||
|
||
internal MessageResponseHelperResult(MessageResponseHelperResultState state, T result) | ||
{ | ||
this.STATE = state; | ||
this.RESULT = result; | ||
} | ||
|
||
#endregion | ||
//--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\ | ||
#region --Set-, Get- Methods-- | ||
|
||
|
||
#endregion | ||
//--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\ | ||
#region --Misc Methods (Public)-- | ||
|
||
|
||
#endregion | ||
|
||
#region --Misc Methods (Private)-- | ||
|
||
|
||
#endregion | ||
|
||
#region --Misc Methods (Protected)-- | ||
|
||
|
||
#endregion | ||
//--------------------------------------------------------Events:---------------------------------------------------------------------\\ | ||
#region --Events-- | ||
|
||
|
||
#endregion | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
XMPP_API/Classes/Network/XML/Messages/Helper/MessageResponseHelperResultState.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
namespace XMPP_API.Classes.Network.XML.Messages.Helper | ||
{ | ||
public enum MessageResponseHelperResultState | ||
{ | ||
/// <summary> | ||
/// The request was successful. | ||
/// </summary> | ||
SUCCESS, | ||
/// <summary> | ||
/// A timeout occurred. | ||
/// </summary> | ||
TIMEOUT, | ||
/// <summary> | ||
/// The helper has been disposed. | ||
/// </summary> | ||
DISPOSED, | ||
/// <summary> | ||
/// An error occurred during sending the message. | ||
/// </summary> | ||
SEND_FAILED, | ||
/// <summary> | ||
/// A general error occurred. | ||
/// </summary> | ||
ERROR, | ||
/// <summary> | ||
/// Sending the message failed, but the message has been cached and will be send later. | ||
/// </summary> | ||
WILL_SEND_LATER | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters