[ejabberd] The case for refactoring MUC

Eric Cestari eric at ohmforce.com
Tue Mar 24 10:40:33 MSK 2009


Hi list,

Here's a proposal for improving mod_muc, and bring it to the  
flexibility of mod_pubsub.
Feedback welcome. I'll open a ticket with a patch for review within a  
few days.

------------------------------------

= Modular MUC =

== Why ? ==

=== Flexible handler ===

MUC in the unsung hero for developping applications buses. Even more  
if they require user interaction.
XEP-0045 sets some base roles for chatting with the default roles and  
affiliations.

But using MUC for playing chess (for example) will require different  
affiliations and message routing should be flexible given a specific  
role.

Jack Moffitt explains the game design of ChessPark (http:// 
chesspark.com) :
http://metajack.im/2008/11/25/chesspark-design-details-part-3-game-design/

     " Another issue is that people watching chess games want to  
discuss the moves, potential tactics, and future plans. Players,  
however, are not allowed to receive advice or help from anyone, so if  
they can see the chat of watchers, then there is a real problem.

     We solved this by making roles affect who sees chat messages. In  
a chess game room, players can send messages and these messages are  
seen by everyone in the room. Regular participants can also talk, but  
only other regular participants can see their messages. A player never  
sees any chat from an observer during a game. Once a game is over, the  
players can see the observers' chat messages. "

ChessPark decided to write its own MUC, Palaver, with twisted, and  
custom roles.

But ejabberd's mod_muc already has all the tools to make that happen.  
It just lacks the flexibility.

=== Modular storage ===

Default storage is mnesia. But it should be possible to store  
persistent rooms using other backends, - RDMSes, Amazon S3 or custom  
webservices.

== Architecture ==

Two behaviours are defined :

=== Storage ===
gen_muc_storage : CRUD methods for storing muc. Config is considered  
opaque.
muc_storage_default, with a mnesia backend is the default  
implementation.

API :
- store_room()
- restore_room()
- forget_room()
- fetch_all_rooms()

That part was easy and done ;)

=== Flexible handler ===
gen_muc_handler : Holds access to configuration. Configuration (the  
current #config record) is opaque to mod_muc_room.
Has functions for :
- Room Access control
- Stanza filtering and custom delivery, based on source and  
destination role and affiliations
- Discovery processing
- building and processing configuration form

There is a default implementation (following exactly XEP-0045) :  
muc_room_default
It should possible for custom handlers to delegate some of their  
behaviours to muc_room_default.
As in mod_pubsub, if a function is not implemented in the custom  
handler it will be reverted to calling muc_room_default.

Parameters passed are subset of the state :
-record(headers, {room,
		host,
		server_host,
		access,
		storage,
		config,
		affiliations = ?DICT:new(),
		subject = "",
		subject_author = ""}).
	
Config, affiliations, subject and subject_author can be modified by  
the handler, by returning the modified record.
Upon change of subject and subject_author or affiliation change,  
modifications are broadcast to the clients.

API (work in progress) :
- get_default_role(Affiliation,#headers{}) -> Role
- process_message(From, To, Message, #headers{}) ->
		{allow, Message, #headers} |
		{filter, Message, fun(),#headers} |  %fun is called for each  
recipient to check for delivery
		{deny, Reason, #headers} |
		{drop, #headers} |
		{error, Error}
- process_presence(From, To, Presence, #headers{}) -> TBD but should  
be pretty much like process_message
- process_iq(From, To, XMLNS, #iq, #headers) -> {ok, Reply, #headers}|  
{error, Message, #headers}
- get_config(#headers) -> Config (adhoc form)
- set_config(FormResult, #headers) -> ok | {error, Message}
- can_invite(From, #headers) -> true | {false, Message}
- can_join(From, #headers) -> true | {false, Message}

== Configuration ==

{mod_muc,      [{storage, s3_muc_storage},{s3_bucket, "chessgame"},
                 {handler, chessgame},
                 {host, "chess. at HOST@"},
                 {access, subscriber},
			    {access_create, paying_subscriber},
			    {access_persistent, paying_subscriber},
			    {access_admin, chess_admin}]}





More information about the ejabberd mailing list