« Archives in November, 2009

Testing new XEPs added on the Ejabberd 2.1.0 final version

+ XEP Support :

  • Added XEP-0059 Result Set Management (for listing rooms)
  • Added XEP-0082 Date Time
  • Added XEP-0085 Chat State Notifications
  • Added XEP-0157 Contact Addresses for XMPP Services
  • Added XEP-0158 CAPTCHA Forms (in MUC rooms)
  • Added STUN server, for XEP-0176: Jingle ICE-UDP Transport Method (skipped this XEP because my system to bad :D )
  • Added XEP-0199 XMPP Ping
  • Added XEP-0202 Entity Time
  • Added XEP-0203 Delayed Delivery
  • Added XEP-0227 Portable Import/Export Format for XMPP-IM Servers
  • Added XEP-0237 Roster Versioning

+ Test enviroment :

  • Server : CPU E2200 @ 2.20GHz x86_64bit 4GB Ram
  • OS : Ubuntu server distro with Linux kernel : 2.6.28-13-generic with GNOME desktop env.
  • Erlang R13B (erts-5.7.1) async-thread:1 kernel-poll:true
  • Ejabberd 2.1.0 final version (virtual host : cuonglb-desktop with one node : ejabberd@localhost)
  • Create two users for this test : user_a@cuonglb-desktop and user_b@cuonglb-desktop
  • PSI 0.12 with XML Console
  • Python 2.5.4 r254:67916 [GCC 4.3.3]
  • Twisted 8.2.0

We are starting with XEP-0199 XMPP Ping:
Open config file of ejabberd at ./conf/ejabberd.cfg and add mod_ping in modules terms (no options):

Erlang
    {modules,
     [
      {mod_adhoc,    []},
      ...
      {mod_ping,    []},
      ...
    ]
    }

Ok, now restart ejabberd server : ./bin/ejabberdctrl restart
Start PSI -> General -> Account setup -> Add account of user a : user_a@cuonglb-desktop and set status is online.
Start PSI:XML Console -> right click on the account user_a@cuonglb-desktop from accounts list and click XML Console.
In XML Console dialog click Enable and click XML Input … button and input xml iq stanza bellow :

Client-to-Server ping

XML
<iq from="cuonglb@cuonglb-desktop/cuonglb-desktop" type="get" to="cuonglb-desktop">
  <ping xmlns='urn:xmpp:ping'/>
</iq>

See on XML Console :

XEP-0157: Contact Addresses for XMPP Services

Queries server with iq stanza :

XML
<iq from='cuonglb@jabber.org/cuongle-lappy'
    to='jabber.org'
    id='disco1'
    type='get'>
  <query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>

My server communicates info

XML
<iq from="jabber.org" type="result" to="cuonglb@jabber.org/cuongle-lappy" id="disco1" >
<query xmlns="http://jabber.org/protocol/disco#info">
<identity category="server" type="im" name="ejabberd" />
<feature var="http://ejabberd.jabberstudio.org/protocol/configure" />
<feature var="http://jabber.org/protocol/commands" />
<feature var="http://jabber.org/protocol/disco#info" />
<feature var="http://jabber.org/protocol/disco#items" />
<feature var="http://jabber.org/protocol/disco#publish" />
<feature var="iq" />
<feature var="jabber:iq:last" />
<feature var="jabber:iq:register" />
<feature var="jabber:iq:time" />
<feature var="jabber:iq:version" />
<feature var="presence" />
<feature var="presence-invisible" />
<feature var="vcard-temp" />
<feature var="http://jabber.org/protocol/commands" />
</query>
</iq>

A look at NOSQL and NOSQL Patterns

Ricky Ho has done a great job of providing a thorough overview of the characteristics and patterns of what are being terms NOSQL products. This includes looking at products purporting to be NOSQL products, API’s ,data partitioning, data replication, client consistency, vector clock, and more. A very good read.

try to develop a sample service using ejabberd router

Today free, try to develop a sample service using ejabberd router.
+ Requirements:

  • Erlang/OTP, XMPP/Jabber protocol and Module development for Ejabberd skills (of course).
  • Jabber clients for testing this service : PSI, Pidgin, Tkabber … I use all :D
  • Mastery of two modules: gen_mod and gen_server behaviour
  • Emacs with Erlang mode (optional, but recommended). :D

+ Using Emacs to creat a file with file name is : mod_sample.erl
+ OK, now we are using emacs/mode to code generation gen_server’s skeleton :D -> Erlang/Skeletons/gen_server

+ Service name : Sample (sample.example.com) with example.com is virtual host.
+ Scope : I do not think but it could be an ejabberd service pattern :D

Erlang
%%%-------------------------------------------------------------------
%%% File    : mod_sample.erl
%%% Author  : Cuong Le <>
%%% Description : ejabberd service using ejabberd_router
%%%
%%% Created : 24 Nov 2009 by Cuong Le <>
%%%-------------------------------------------------------------------
-module(mod_sample).
 
-behaviour(gen_server).
-behaviour(gen_mod).
 
%% API
-export([start_link/2]).
 
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
   terminate/2, code_change/3]).
 
%% gen_mod callbacks
-export([start/2,stop/1]).
 
-define(PROCNAME, ejabberd_mod_sample).
 
-record(state, {
host
}).
 
-include("ejabberd.hrl").
-include("jlib.hrl").
 
%%====================================================================
%% API
%%====================================================================
 
%%--------------------------------------------------------------------
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
%% Description: Starts the server
%%--------------------------------------------------------------------
 
start_link(Host, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []).
 
%%====================================================================
%% gen_mod callbacks
%%====================================================================
start(Host, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
ChildSpec = {Proc, {?MODULE, start_link, [Host, Opts]}, permanent, 1000, worker, [?MODULE]},
supervisor:start_child(ejabberd_sup, ChildSpec).
 
stop(Host)->
    Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
    supervisor:terminate_child(ejabberd_sup, Proc),
    supervisor:delete_child(ejabberd_sup, Proc).
%%====================================================================
%% gen_server callbacks
%%====================================================================
%%--------------------------------------------------------------------
%% Function: init(Args) -> {ok, State} |
%%                         {ok, State, Timeout} |
%%                         ignore               |
%%                         {stop, Reason}
%% Description: Initiates the server
%%--------------------------------------------------------------------
 
init([Host, Opts]) ->
 
MyHost = gen_mod:get_opt_host(Host, Opts, "sample.@HOST@"),
 
ejabberd_router:register_route(MyHost),
 
{ok, #state{
host = MyHost
}}.
 
%%--------------------------------------------------------------------
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
%%                                      {reply, Reply, State, Timeout} |
%%                                      {noreply, State} |
%%                                      {noreply, State, Timeout} |
%%                                      {stop, Reason, Reply, State} |
%%                                      {stop, Reason, State}
%% Description: Handling call messages
%%--------------------------------------------------------------------
 
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
 
%%--------------------------------------------------------------------
%% Function: handle_cast(Msg, State) -> {noreply, State} |
%%                                      {noreply, State, Timeout} |
%%                                      {stop, Reason, State}
%% Description: Handling cast messages
%%--------------------------------------------------------------------
 
handle_cast(_Msg, State) ->
{noreply, State}.
 
%%--------------------------------------------------------------------
%% Function: handle_info(Info, State) -> {noreply, State} |
%%                                       {noreply, State, Timeout} |
%%                                       {stop, Reason, State}
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
 
handle_info({route, From, To, Packet}, #state{host = Host} = State) ->
    case catch do_route(From, To, Packet, Host) of
  {'EXIT', Reason}->
      ?ERROR_MSG("~p",[Reason]);
  _ ->
      ok
    end,
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
 
%%--------------------------------------------------------------------
%% Function: terminate(Reason, State) -> void()
%% Description: This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any necessary
%% cleaning up. When it returns, the gen_server terminates with Reason.
%% The return value is ignored.
%%--------------------------------------------------------------------
 
terminate(_Reason, State) ->
ejabberd_router:unregister_route(State#state.host),
ok.
 
%%--------------------------------------------------------------------
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
 
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
 
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
 
do_route(From, To, Packet, Host)->
    {xmlelement, Name, Attrs, _Els} = Packet,
    case To of 
  #jid{luser = "", lresource = ""} ->
      case Name of
    "iq" ->        
        case jlib:iq_query_info(Packet) of
      #iq{type=get, xmlns = ?NS_DISCO_INFO, sub_el = SubEl, lang = Lang} = IQ ->
          {xmlelement, _, QAttrs, _} = SubEl,
          Node = xml:get_attr_s("node", QAttrs),
          Res = case iq_disco_info(Host, Node, From, Lang) of
              {result, IQRes} ->
            jlib:iq_to_xml(
              IQ#iq{type = result,
              sub_el = [{xmlelement, "query",
                   QAttrs, IQRes}]});
              {error, Error} ->
            jlib:make_error_reply(Packet, Error)
          end,
          ejabberd_router:route(To, From, Res);            
      #iq{} ->
          Err = jlib:make_error_reply(
            Packet,
            ?ERR_FEATURE_NOT_IMPLEMENTED),
          ejabberd_router:route(To, From, Err);          
      _ ->            
          ok
        end;       
    _ ->
        ok
      end;
  _ ->
      ok
    end.
 
string_to_node(SNode) ->
    string:tokens(SNode, "/").
 
iq_disco_info(Host, SNode, From, _Lang) ->
    Node = string_to_node(SNode),
    case Node of
  [] ->
      {result,
       [{xmlelement, "identity",
         [{"category", "test"},
    {"type", "service"},
    {"name", "sample"}], []}]
      };
  _ ->
      ok  
    end.

To be continue … :D