Skip to content

Instantly share code, notes, and snippets.

@paulrobello
Created January 29, 2024 21:59
Show Gist options
  • Save paulrobello/d8e0ad6c54578ddfa1bc078d100bd580 to your computer and use it in GitHub Desktop.
Save paulrobello/d8e0ad6c54578ddfa1bc078d100bd580 to your computer and use it in GitHub Desktop.
Websocket message subscription filter
using System;
using System.Collections.Generic;
using System.Linq;
namespace Websocket
{
public interface IWsMessageFilterPredicate
{
bool Evaluate(IWsMessage msg);
}
// This filter will always evaluate to true
public class WsNullFilter : IWsMessageFilterPredicate
{
public bool Evaluate(IWsMessage msg)
{
return true;
}
}
// Evaluates to true if all predicates evaluate to true
public class WsAndFilter : IWsMessageFilterPredicate
{
private readonly List<IWsMessageFilterPredicate> _predicates = new();
public bool Evaluate(IWsMessage msg)
{
return _predicates.All(predicate => predicate.Evaluate(msg));
}
public WsAndFilter AddPredicate(IWsMessageFilterPredicate predicate)
{
_predicates.Add(predicate);
return this;
}
public WsAndFilter()
{
}
public WsAndFilter(IWsMessageFilterPredicate predicate)
{
_predicates.Add(predicate);
}
}
// Evaluates to true if any predicate evaluates to true
public class WsOrFilter : IWsMessageFilterPredicate
{
private readonly List<IWsMessageFilterPredicate> _predicates = new();
public bool Evaluate(IWsMessage msg)
{
return _predicates.Any(predicate => predicate.Evaluate(msg));
}
public WsOrFilter AddPredicate(IWsMessageFilterPredicate predicate)
{
_predicates.Add(predicate);
return this;
}
public WsOrFilter()
{
}
public WsOrFilter(IWsMessageFilterPredicate predicate)
{
_predicates.Add(predicate);
}
}
// Evaluates to true if the predicate evaluates to false
public class WsNotFilter : IWsMessageFilterPredicate
{
private readonly IWsMessageFilterPredicate _predicate;
public bool Evaluate(IWsMessage msg)
{
return !_predicate.Evaluate(msg);
}
public WsNotFilter(IWsMessageFilterPredicate predicate)
{
_predicate = predicate;
}
}
// Evaluates to true if the message type matches
public class WsMsgTypeFilter : IWsMessageFilterPredicate
{
private readonly string _msgType;
public bool Evaluate(IWsMessage msg)
{
return _msgType == null || msg.MsgType == _msgType;
}
public WsMsgTypeFilter(string topic)
{
_msgType = topic;
}
}
// Evaluates to true if the topic matches
public class WsMessageTopicFilter : IWsMessageFilterPredicate
{
private readonly string _topic;
public bool Evaluate(IWsMessage msg)
{
return _topic == null || msg.Topic == _topic;
}
public WsMessageTopicFilter(string topic)
{
_topic = topic;
}
}
// Evaluates to true if the request id matches
public class WsMessageRequestIdFilter : IWsMessageFilterPredicate
{
private readonly string _requestId;
public bool Evaluate(IWsMessage msg)
{
return _requestId == null || msg.RequestId == _requestId;
}
public WsMessageRequestIdFilter(string requestId)
{
_requestId = requestId;
}
}
// Invokes callback if all predicates evaluate to true
public class WsMessageFilter
{
private readonly WsAndFilter _predicates = new();
// The callback will be invoked when the filter evaluates to true
private Action<WsMessage> _callback;
// If Once is true, the callback will be invoked at most once before being removed from the list of subscribers
public bool Once { get; private set; }
// Returns true if all predicates evaluate to true
public bool Evaluate(IWsMessage msg) => _predicates.Evaluate(msg);
public WsMessageFilter AddPredicate(IWsMessageFilterPredicate predicate)
{
_predicates.AddPredicate(predicate);
return this;
}
public WsMessageFilter SetCallback<T>(Action<T> callback) where T : WsMessage
{
_callback = msg => callback(msg as T);
return this;
}
private void InvokeCallback(WsMessage msg)
{
_callback?.Invoke(msg);
}
public WsMessageFilter SetOnce(bool once)
{
Once = once;
return this;
}
public WsMessageFilter()
{
}
public WsMessageFilter(Action<WsMessage> callback, bool once = false)
{
_callback = callback;
Once = once;
}
public bool InvokeIfMatch(WsMessage msg)
{
if (!Evaluate(msg)) return false;
InvokeCallback(msg);
return true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment