Closed postacik closed 4 years ago
Hello @postacik ,
is this the behavior of the code on master? I'm afraid the nugget is still not up to date...
Hi @Florimond ,
I just downloaded the master channel code and ran the following test code:
using (var emitter = Connection.Establish(channelKey, "localhost", 8082, false))
{
emitter.Subscribe(channel,
(chan, msg) => { Console.WriteLine("Handler1 :" + Encoding.UTF8.GetString(msg)); });
emitter.Subscribe(channel,
(chan, msg) => { Console.WriteLine("Handler2 :" + Encoding.UTF8.GetString(msg)); });
string text = "";
Console.WriteLine("Type to chat or type 'q' to exit...");
do
{
text = Console.ReadLine();
emitter.Publish(channelKey, channel, text, Options.WithTTL(3600));
}
while (text != "q");
}
Here's the output:
Type to chat or type 'q' to exit...
postacik
Handler1 :postacik
message
Handler1 :message
test
Handler1 :test
Only "Handler1" is triggered.
However, in my application, the same channel is subscribed in different classes and they update their user interface from the message respectively. So I need all handlers to be triggered.
If I remember correctly, the handler should be updated so the second handler is called instead of the first one. That might be a bug indeed.
However, there is only one handler per channel. It's designed like that in the other SDKs as well. There is one consumer per channel and unsubscribing is therefore straightforward. Can't you achieve what you want with the sub-channel mechanism?
I have my own JavaScript, C# and Dart libraries.
I had copied the ReverseTrie algorithm from an old version of this project and in my implementations the second handler overrides the first one as you mentioned and only the last inline handler is triggered.
Anyway, if your latest implementation also has a similar behavior and if that's by design, I have to improve my ReverseTrie algorithm.
Thanks :)
Here's my ReverseTrie implementation which supports multiple subscriptions and inline message handlers for a channel:
public class ReverseTrie<T> where T : class
{
private readonly Hashtable Children;
private readonly int Level = 0;
private List<T> Value = default(List<T>);
public ReverseTrie(int level)
{
this.Level = level;
this.Children = new Hashtable();
}
public void RegisterHandler(string channel, T value)
{
this.Add(CreateKey(channel), 0, value);
}
public void UnregisterHandler(string channel)
{
this.TryRemove(CreateKey(channel), 0);
}
private List<T> RecurMatch(string[] query, int posInQuery, Hashtable children)
{
var matches = new List<T>();
if (posInQuery == query.Length)
return matches;
if (Utils.TryGetValueFromHashtable(children, "+", out object objPlusChildNode))
{
var childNode = objPlusChildNode as ReverseTrie<T>;
if (childNode.Value != default(List<T>))
matches.AddRange(childNode.Value);
matches.AddRange(RecurMatch(query, posInQuery + 1, childNode.Children));
}
if (Utils.TryGetValueFromHashtable(children, query[posInQuery], out object objQueryChildNode))
{
var childNode = objQueryChildNode as ReverseTrie<T>;
if (childNode.Value != default(List<T>))
matches.AddRange(childNode.Value);
matches.AddRange(RecurMatch(query, posInQuery + 1, childNode.Children));
}
return matches;
}
public List<T> Match(string channel)
{
var query = CreateKey(channel);
var result = RecurMatch(query, 0, this.Children);
return result;
}
public static string[] CreateKey(string channel)
{
return channel.Trim('/').Split('/');
}
private object Add(string[] key, int position, T value)
{
if (position == key.Length)
{
lock (this)
{
// There's already a value
if (this.Value == default(List<T>))
this.Value = new List<T>();
this.Value.Add(value);
return this.Value;
}
}
// Create a child
var child = Utils.GetOrAddToHashtable(Children, key[position], new ReverseTrie<T>(position)) as ReverseTrie<T>;
return child.Add(key, position + 1, value);
}
private bool TryRemove(string[] key, int position)
{
if (position == key.Length)
{
lock (this)
{
if (this.Value == default(List<T>))
return false;
this.Value = default(List<T>);
return true;
}
}
// Remove from the child
object child;
if (Utils.TryGetValueFromHashtable(Children, key[position], out child))
return ((ReverseTrie<T>)child).TryRemove(key, position + 1);
return false;
}
}
I only glanced over the code... You can add several handlers to a node indeed, but it doesn't seem like you have the choice to remove only one specific handler with this solution. You seem remove all handlers at once. Which solution I'm not fond of...
You are right but if you unsubscribe a channel, all of the handlers can be disposed because you'll not receive any more events from the emitter server. That's what the given code does. Clears all handlers if unsubscribed.
Hi, When the code above is executed and a message arrives on "channel/", only the second handler is fired.
Is this the expected behavior or a bug?