Experimental MIX Support for Group Conversations added to ejabberd

MIX stands for Mediated Information eXchange and is defined in draft of XEP-0369.

It is a work in progress extension for the XMPP protocol to build a group messaging protocol that does not rely on the presence mechanism. It is designed to overcome the limitation of XEP-0045 Multi-User Chat, in a context where most clients are mobile clients.

To do so, MIX is built on top of PubSub (XEP-0060) and use different nodes per channel to separate event types. There is five nodes to support five different types of event for each MIX conversation:

  • Messages
  • Presence
  • Participant list changes
  • Subject update
  • Conversion configuration changes

This is a work in progress, but this is a very important task and we are happy to provide the very first server implementation of the Mix protocol to get up to speed on that specification.

Here is a short walk through what can already be done.

Please, note that this is a work in progress and that the specification can (and will) change significantly before it becomes stable. This blog post is based on XEP-0369 v0.1.

Configuration

Configuration is simple:

  • You need to build ejabberd from source, latest master version.
  • You need to add mod_mix in ejabberd configuration, modules section:

    modules:
      mod_mix: {}
    
  • Make sure you have pubsub enabled. Default configuration is fine:

    modules:
      mod_pubsub: 
        access_createnode: pubsub_createnode
        ignore_pep_from_offline: true
        last_item_cache: false
        plugins: 
          - "flat"
          - "hometree"
          - "pep"
    

Usage

There is no client supporting MIX yet so here is how it works directly at XMPP stream level.

Here are real-life examples from playing with our MIX implementation:

Joining a MIX conversation

You can join a MIX conversation if you know its jid (id@mixservice):

You can send a join IQ:

<iq type='set'
    to='hellomix@mix.localhost'
    id='E6E10350-76CF-40C6-B91B-1EA08C332FC7'>
  <join xmlns='urn:xmpp:mix:0'>
    <subscribe node='urn:xmpp:mix:nodes:messages'></subscribe>
    <subscribe node='urn:xmpp:mix:nodes:presence'></subscribe>
    <subscribe node='urn:xmpp:mix:nodes:participants'></subscribe>
    <subscribe node='urn:xmpp:mix:nodes:subject'></subscribe>
    <subscribe node='urn:xmpp:mix:nodes:config'></subscribe>
  </join>
</iq>

You receive IQ that confirms success:

<iq from="HelloMix@mix.localhost" type="result" to="admin@localhost/MacBook-Pro-de-Mickael" id="E6E10350-76CF-40C6-B91B-1EA08C332FC7">
 <join xmlns="urn:xmpp:mix:0" jid="admin@localhost">
  <subscribe node="urn:xmpp:mix:nodes:messages"></subscribe>
  <subscribe node="urn:xmpp:mix:nodes:presence"></subscribe>
  <subscribe node="urn:xmpp:mix:nodes:participants"></subscribe>
  <subscribe node="urn:xmpp:mix:nodes:subject"></subscribe>
  <subscribe node="urn:xmpp:mix:nodes:config"></subscribe>
 </join>
</iq>

Subscribers on the participants node for that channel will also receive the new list of participants (so, including ourselves in that case):

<message from="hellomix@mix.localhost" type="headline" to="admin@localhost/MacBook-Pro-de-Mickael">
 <event xmlns="https://jabber.org/protocol/pubsub#event">
  <items node="urn:xmpp:mix:nodes:participants">
   <item id="3d1766e2bd1b02167104f350f84b0668f850ef92">
    <participant xmlns="urn:xmpp:mix:0" jid="admin@localhost"></participant>
   </item>
  </items>
 </event>
</message>

Note: Nickname registration support is not yet implemented in our code.

Sending and receiving messages

You can now start chatting with your peers, by publishing on the message node:

<iq type='set'
    to='HelloMix@mix.localhost'
    id='mix2'>
  <pubsub xmlns='https://jabber.org/protocol/pubsub'>
    <publish node='urn:xmpp:mix:nodes:messages'>
      <item>
        <body xmlns='jabber:client'>Hi, there !</body>
      </item>
    </publish>
  </pubsub>
</iq>

Server confirms publishing:

<iq from="HelloMix@mix.localhost" type="result" to="admin@localhost/MacBook-Pro-de-Mickael" id="mix2">
 <pubsub xmlns="https://jabber.org/protocol/pubsub">
  <publish node="urn:xmpp:mix:nodes:messages">
   <item id="5B1AB7F432DA5"></item>
  </publish>
 </pubsub>
</iq>

Message is received by all subscribers on the message node on that MIX conversation:

<message from="hellomix@mix.localhost" type="headline" to="admin@localhost/MacBook-Pro-de-Mickael">
 <event xmlns="https://jabber.org/protocol/pubsub#event">
  <items node="urn:xmpp:mix:nodes:messages">
   <item id="5B1AB7F432DA5">
    <body xmlns="jabber:client">Hi, there !</body>
   </item>
  </items>
 </event>
</message>

Sending and receiving presence

The presence in MIX conversation is conceptually independent from presence stanzas in standard XMPP protocol. In MIX, the presence is simply a state you want to broadcast to the subscribers of the presence node in the conversation.

The presence is broadcast through the Mix conversion, in a similar way to message:

<iq type='set'
    to='HelloMix@mix.localhost'
    id='mix3'>
  <pubsub xmlns='https://jabber.org/protocol/pubsub'>
    <publish node='urn:xmpp:mix:nodes:presence'>
      <item>
        <presence xmlns='jabber:client'>
          <c xmlns='https://jabber.org/protocol/caps'
             hash='sha-1'
             node='https://code.google.com/p/exodus'
             ver='QgayPKawpkPSDYmwT/WM94uAlu0='></c>
        </presence>
      </item>
    </publish>
  </pubsub>
</iq>

As you can see, presence is model on XMPP presence specification. In that case, we included caps info for example in our broadcast.

Server confirms presence broadcast to sender:

<iq from="HelloMix@mix.localhost" type="result" to="admin@localhost/MacBook-Pro-de-Mickael" id="mix3">
 <pubsub xmlns="https://jabber.org/protocol/pubsub">
  <publish node="urn:xmpp:mix:nodes:presence">
   <item id="5B1ACB064CE"></item>
  </publish>
 </pubsub>
</iq>

And finally, participants to conversation subscribe to presence will receive presence update:

<message from="hellomix@mix.localhost" type="headline" to="admin@localhost/MacBook-Pro-de-Mickael">
 <event xmlns="https://jabber.org/protocol/pubsub#event">
  <items node="urn:xmpp:mix:nodes:presence">
   <item id="5B1ACB064CE">
    <presence xmlns="jabber:client">
     <c xmlns="https://jabber.org/protocol/caps" node="https://code.google.com/p/exodus" ver="QgayPKawpkPSDYmwT/WM94uAlu0=" hash="sha-1"></c>
    </presence>
   </item>
  </items>
 </event>
</message>

The presence at the moment is somewhat in between in current state of the XEP. To retract the presence you send a standard XMPP presence of type unavailable:

<presence type='unavailable'
          to='HelloMix@mix.localhost'></presence>

Server confirms retracting the presence item:

<message from="hellomix@mix.localhost" type="headline" to="test@localhost/MacBook-Pro-de-Mickael">
 <event xmlns="https://jabber.org/protocol/pubsub#event">
  <items node="urn:xmpp:mix:nodes:presence">
   <retract id="5B1ACB064CE"></retract>
  </items>
 </event>
</message>

This part is still unfortunate as it still makes it difficult to manage presence on mobiles were the status, that is the ability to receive messages, is somewhat disconnected from the session state. This is likely an area that will change significantly in the future.

Another thing to note is that for the moment, all your presence publications are kept as items, but going offline retract them all.

Querying participants list

A participant can always get list of participants with a Pubsub query on node items for the conversation:

<iq type='get'
    to='HelloMix@mix.localhost'
    id='mix4'>
  <pubsub xmlns='https://jabber.org/protocol/pubsub'>
    <items node='urn:xmpp:mix:nodes:participants'></items>
  </pubsub>
</iq>

The conversation will reply with list of participants:

<iq from="HelloMix@mix.localhost" type="result" to="admin@localhost/MacBook-Pro-de-Mickael" id="mix4">
 <pubsub xmlns="https://jabber.org/protocol/pubsub">
  <items node="urn:xmpp:mix:nodes:participants">
   <item id="1a3b7690ea2608d13988aca8339acf759daa8483">
    <participant xmlns="urn:xmpp:mix:0" jid="test@localhost"></participant>
   </item>
   <item id="3d1766e2bd1b02167104f350f84b0668f850ef92">
    <participant xmlns="urn:xmpp:mix:0" jid="admin@localhost"></participant>
   </item>
  </items>
 </pubsub>
</iq>

Querying the presence

You can query the presence as well:

<iq type='get'
    to='HelloMix@mix.localhost'
    id='mix5'>
  <pubsub xmlns='https://jabber.org/protocol/pubsub'>
    <items node='urn:xmpp:mix:nodes:presence'></items>
  </pubsub>
</iq>

and you get a list of “available” users:

<iq from="HelloMix@mix.localhost" type="result" to="admin@localhost/MacBook-Pro-de-Mickael" id="mix5">
 <pubsub xmlns="https://jabber.org/protocol/pubsub">
  <items node="urn:xmpp:mix:nodes:presence">
   <item id="5B1ADB972CEC">
    <presence xmlns="jabber:client">
     <c xmlns="https://jabber.org/protocol/caps" node="https://code.google.com/p/exodus" ver="QgayPKawpkPSDYmwT/WM94uAlu0=" hash="sha-1"></c>
    </presence>
   </item>
  </items>
 </pubsub>
</iq>

Getting the list of messages

With a similar pubsub query, you can retrieve the list of messages:

<iq type='get'
    to='HelloMix@mix.localhost'
    id='mix5'>
  <pubsub xmlns='https://jabber.org/protocol/pubsub'>
    <items node='urn:xmpp:mix:nodes:messages'></items>
  </pubsub>
</iq>

Server replies with list of messages:

<iq from="HelloMix@mix.localhost" type="result" to="admin@localhost/MacBook-Pro-de-Mickael" id="mix5">
 <pubsub xmlns="https://jabber.org/protocol/pubsub">
  <items node="urn:xmpp:mix:nodes:messages">
   <item id="5B1ABD0BD973D">
    <body xmlns="jabber:client">Hi, there is is test !</body>
   </item>
   <item id="5B1AB7F432DA5">
    <body xmlns="jabber:client">Hi, there !</body>
   </item>
  </items>
 </pubsub>
</iq>

As you can see there, there is need for improvement to rely on this list for history of messages. First, you do not have message attribution (see Caveats section), but this can be worked out.
Also, you do not have timestamp on the messages.

This part will likely change a lot in the future. I expect that a link with Message Archive Management support will be a more efficient and more consistent way to deal with message history.

Caveats

At the moment it is unclear from XEP-0369 example how you match a message you receive to a participant. We are going to improve our implementation in the following way:

  1. Add a participant id on the item tag when broadcasting new participant.
  2. Add the participant id on the published items.
  3. Add the participant id in participants list on the publisher

Another issue is that the current specification and implementation will have trouble scaling and offer plenty of opportunities for “Denial of Service” attacks. This is something that will change in the future as the specification matures. However, currently, do not deploy or rely on this implementation for large-scale production services. The work is still an experiment to progress on the specifications by offering client developers to give real life feedback on a reference implementation of the current specification.

Conclusion

We are only at the beginning of MIX. However, we are excited to have reached a point where it is already usable in some cases.

It is still missing on administrative tasks, right management, user invitations, relationship with MAM archiving and probably a lot more. And we need consolidations on participants message attribution. However, we want to iterate fast with client developers to prototype implementation changes and have meaningful and real life feedback to improve XEP-0359.

Send us your feedback !


Let us know what you think 💬


5 thoughts on “Experimental MIX Support for Group Conversations added to ejabberd

  1. Thanks for the effort! I notice that messages are distributed to participants with ‘headline’ type. Is it possibile to store them to offline storage?

Leave a Comment


This site uses Akismet to reduce spam. Learn how your comment data is processed.