I am creating a messaging system and I am facing a problem. I need to Publish a message and wait for the response before returning the Publish function.
This is what my functions look like
public async Task<bool> Publish(int ClientId, string msg){
...
// Wait and check if the client the message was sent to respond
// if that does not happen within 5 seconds, return false, else true
}
private async Task MessageIntercept(int ClientId, string msg){
// Intercepts all messages
...
}
Both of these functions are on the server and the MessageIntercept task is automatically run whenever a message is sent (including the one sent with the Publish method). I can send a message from my asp.net website project by calling on the server project's Publish function mentioned above
Basically what i want to be able to do is call bool Success = Publish(1,"This is a test")
and be able to determine whether or not the message was successfully sent, that the client understood and revived the message within 5 seconds.
This is what happens step by step:
Publish
MessageIntercept
method (which I do not really care about, but the code is written so that all messages are intercepted)MessageIntercept
which is where I would like to verify the message before returning the Publish
methodExample Message;
Server Message:
{
ClientId: 13,
msg: "Hello World"
}
Client Response:
{
ClientId: 13,
msg: "{Success: true}"
}
MessageIntercept
intercepts all messages, including the request just send which should be ignored due to it beeing a request not a response. However once the client responds with a message would I like to tell the Publish method that the response has been successfully completed and then return true. Else if the client does not respond within 5 seconds it should presume false.
There is nothing for Publish to wait on, so you need to add a notification hook. An event like "OnMessageIntercept" makes sense to me.
You can then wait on a Task that will be completed by a call to the notification hook.
public async Task<bool> PublishAsync(int clientId, string msg)
{
// Wait and check if the client the message was sent to respond
// if that does not happen within 5 seconds, return false, else true
var messageRecievedSource = new TaskCompletionSource<int>();
void intercept(object sender, MessageInterceptEventArgs args)
{
if (args.ClientId == clientId)
messageRecievedSource.SetResult(clientId);
}
OnMessageIntercept += intercept;
// EDIT
// var completed = Task.WaitAny(Task.Delay(TimeSpan.FromSeconds(5)), messageRecievedSource.Task) > 0;
var completed = await Task.WhenAny(Task.Delay(TimeSpan.FromSeconds(5)), messageRecievedSource.Task);
OnMessageIntercept -= intercept;
// EDIT
// return completed;
return completed == messageRecievedSource.Task;
}
event EventHandler<MessageInterceptEventArgs> OnMessageIntercept;
private async Task MessageIntercept(int clientId, string msg)
{
OnMessageIntercept?.Invoke(this, new MessageInterceptEventArgs(clientId, msg));
// Intercepts all messages
}
class MessageInterceptEventArgs
{
public MessageInterceptEventArgs(int clientId, string msg)
{
ClientId = clientId;
Msg = msg ?? throw new ArgumentNullException(nameof(msg));
}
public int ClientId { get; }
public string Msg { get; }
}