Not logged in. · Lost password · Register
Forum: MatriX and XmppDotNet RSS
Avatar
johnm60 #1
Member since Jun 2010 · 32 posts
Group memberships: Members
Show profile · Link to this post
Thanks again. I looking again at a solution to this problem, I have now managed to either break my application or expose an existing flaw that I had not realised was there. I am not sure which one at the moment. If you will bear with me, I will try to explain what I am observing and that this is questioning my understanding of how Matrix does Iq filters.

The application I am building is a pair of applications that exchange messages bi-directionally - that is both ends are the service consumer and provider for the same message types.

On an originating end, I do something like:

  1. void sendMessage(string destination, string filename, string contents)
  2.         {
  3.             var diq = new DispatcherIq
  4.             {
  5.                 Type = Matrix.Xmpp.IqType.set,
  6.                 To = destination + "/" + clState.Resource,
  7.                 Dispatcher = new Dispatcher { SenderMAN = clState.Username, RecipientMAN = destination, Filename = filename, MessageBody = fu.getBase64Contents(contents) }
  8.             };
  9.             // we pass the filename as state object to the IqFilter
  10.             clState.Client.IqFilter.SendIq(diq, DispatcherResponse,filename);
  11.         }

Here the method "DispatcherResponse" will then process a "success" variant of the "Dispatcher" message.

On the receiving end I have a method (using your callback filter class) that accepts Dispatcher requests and then (after the real work) send the success response. Something like this:
  1. private void DispatcherCallback(object sender, IqEventArgs e)
  2.         {
  3.             if (e.Iq.Type == Matrix.Xmpp.IqType.set && e.Iq.Query is Dispatcher)
  4.             {
  5.                 var dispatcher = e.Iq.Query as Dispatcher;
  6.                 // do some interesting work
  7.                 //now send response
  8.                 var diq = new DispatcherIq
  9.                 {
  10.                     Id = e.Iq.Id,  //used to correlate with the request !!!
  11.                     To = e.Iq.From,
  12.                     Type = Matrix.Xmpp.IqType.result,
  13.                     Dispatcher = new Dispatcher { Filename = dispatcher.Filename, MessageBody = "success", SenderMAN = e.Iq.From.ToString(), RecipientMAN = e.Iq.To.ToString() }
  14.                 };
  15.                 // send the response
  16.                 clState.Client.Send(diq);
  17.             }
  18.             else
  19.             {
  20.                 logger.Error("Dispatcher callback Iq received, but can't marshal {0}", e.Iq.ToString());
  21.             }        
  22.         }

To complete the picture, back on the originating end, the DispatcherResponse, looks like this:

  1. private void DispatcherResponse(object sender, Matrix.Xmpp.Client.IqEventArgs e)
  2.         {
  3.             var iq = e.Iq;
  4.             if (iq.Type == Matrix.Xmpp.IqType.result)
  5.             {
  6.                 var dispatcher = iq.Element<Dispatcher>();
  7.                 if (dispatcher != null)
  8.                 {
  9.                     //I now know I have the response and so clean-up
  10.                 }
  11.                 else
  12.                 {
  13.                     logger.Error("Dispatcher response Iq received, but can't marshal {0}", e.Iq.ToString());
  14.                 }
  15.             }
  16.             else
  17.             {
  18.                 logger.Error("Dispatcher response Error received {0}", e.Iq.ToString());
  19.             }
  20.         }


What I am seeing in my logs is that the DispatcherCallback (on the originator-side) is picking up the success response and not the DispatcherResponse method. I have been using a variation of this code for some weeks, but I have only just added enough diagnostics to see this behaviour (or I may have recently added this "feature").

Back to the questions:

1. How does Matrix make sure that the correct (or intended) method is called? Does setting up the Iq filter take precedence over the main On_Iq?
2. How does Matrix correlate requests with responses? Here the view has to be that it is matching message IDs. Is this the case?
3. If it is matching message IDs, how does one circumvent a pair of clients each generating its own (unique to it) but not unique across clients? I know I can set the ID with a GUID, but is this accepted practice?
4. The clState.Client.IqFilter.SendIq method has two separate implementations, one that takes the callback and the other the "Object state". What is the latter for and will this help?
 
Thanks again.
John
Avatar
Alex #2
Member since Feb 2003 · 4449 posts · Location: Germany
Group memberships: Administrators, Members
Show profile · Link to this post
there is a internal collection which maps the ids and callbacks. When an iq with an id we are looking for the callback is raised and it gets removed from the collection.

In my latest developer code I optimized the IqFilter code, but in the current version there can be race conditions like you have them. Please use unique ids until I release a new binary which ignores get and set Iqs in the filtering logic.

Set this once in your code:
  1. MatriX.Id.Type = IdType.Guid;

I also consider switching to unique ids by default in the next release.

Alex
Avatar
johnm60 #3
Member since Jun 2010 · 32 posts
Group memberships: Members
Show profile · Link to this post
Thanks again Alex.

I have now implemented the IdType.Guid and also been less aggressive with my re-try code and things seem better. Just to clear up my understanding, it it the case that the callback in the IqFilter gets called first and then the OnIq later - for the same Iq (hence me seeing the Is in the DispatcherResponse and then the DispatcherCallback in my example)?

Regards
John
Avatar
Alex #4
Member since Feb 2003 · 4449 posts · Location: Germany
Group memberships: Administrators, Members
Show profile · Link to this post
Quote by johnm60:
Just to clear up my understanding, it it the case that the callback in the IqFilter gets called first and then the OnIq later - for the same Iq (hence me seeing the Is in the DispatcherResponse and then the DispatcherCallback in my example)?
this correct correct. The IqFiler has a reference and subscribes to the Oniq event to filter out the Iqs you subscribed to. Its by design that the same packet appear in different callbacks. Its similar to routed events in WPF. I thought about a Handled property in the EventArgs. Then you can know that the packet was already handled and you don't have to perform any action in the other events and can exit the function. I wrote many complex apps with MatriX, but never had problems with this behavior. If this would be useful for other developers or there are other reasons for adding it I will put in on my TODO list.
Close Smaller – Larger + Reply to this post:
Verification code: VeriCode Please enter the word from the image into the text field below. (Type the letters only, lower case is okay.)
Smileys: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Special characters: