<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Richard Jones, Esq. &#187; mnesia</title>
	<atom:link href="http://www.metabrew.com/article/tag/mnesia/feed" rel="self" type="application/rss+xml" />
	<link>http://www.metabrew.com</link>
	<description>Erlang, PHP, C, C++, Java, PostgreSQL, MySQL, Hadoop, Linux, awk, bash, sed, grep, screen, vim, irc, ssh etc...</description>
	<lastBuildDate>Sun, 20 Dec 2009 18:59:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Getting to know ejabberd and writing modules</title>
		<link>http://www.metabrew.com/article/getting-to-know-ejabberd-and-writing-modules/</link>
		<comments>http://www.metabrew.com/article/getting-to-know-ejabberd-and-writing-modules/#comments</comments>
		<pubDate>Sun, 23 Nov 2008 21:53:17 +0000</pubDate>
		<dc:creator>RJ</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[ejabberd]]></category>
		<category><![CDATA[erlang]]></category>
		<category><![CDATA[mnesia]]></category>
		<category><![CDATA[thrift]]></category>
		<category><![CDATA[xmpp]]></category>
		<category><![CDATA[yaws]]></category>

		<guid isPermaLink="false">http://www.metabrew.com/?p=203</guid>
		<description><![CDATA[I started poking around in the ejabberd source code to see what I could learn. I couldn&#8217;t find much in the way of high level documentation that talks about how the various bits of ejabberd talk to each other, so I&#8217;m starting to piece it together myself. After compiling ejabberd I made a php script [...]]]></description>
			<content:encoded><![CDATA[<p>I started poking around in the ejabberd source code to see what I could learn. I couldn&#8217;t find much in the way of high level documentation that talks about how the various bits of ejabberd talk to each other, so I&#8217;m starting to piece it together myself.</p>
<p>After compiling ejabberd I made a php script I could use with the external authentication system. Here&#8217;s a version that supports just two hardcoded users:</p>
<p>ejabberd.cfg:<br />
<code>{auth_method, external}.<br />
{extauth_program, "/tmp/auth.php"}.</code><br />
<br/></p>
<p>auth.php:</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="co2">#!/usr/bin/php</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">&lt;?</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$fh</span> &nbsp;= <a href="http://www.php.net/fopen"><span class="kw3">fopen</span></a><span class="br0">&#40;</span><span class="st0">&quot;php://stdin&quot;</span>, <span class="st0">&#8216;r&#8217;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span>!<span class="re0">$fh</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <a href="http://www.php.net/die"><span class="kw3">die</span></a><span class="br0">&#40;</span><span class="st0">&quot;Cannot open STDIN<span class="es0">\n</span>&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$users</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st0">&#8216;user1&#8242;</span>=&gt;<span class="st0">&#8216;password1&#8242;</span>, <span class="st0">&#8216;user2&#8242;</span>=&gt;<span class="st0">&#8216;password2&#8242;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">do</span><span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$lenBytes</span> = <a href="http://www.php.net/fgets"><span class="kw3">fgets</span></a><span class="br0">&#40;</span><span class="re0">$fh</span>, <span class="nu0">3</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$len</span> = <a href="http://www.php.net/unpack"><span class="kw3">unpack</span></a><span class="br0">&#40;</span><span class="st0">&#8216;n&#8217;</span>, <span class="re0">$lenBytes</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$len</span> = <span class="re0">$len</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$len</span>&lt;<span class="nu0">1</span><span class="br0">&#41;</span> <span class="kw1">continue</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$msg</span> = <a href="http://www.php.net/fgets"><span class="kw3">fgets</span></a><span class="br0">&#40;</span><span class="re0">$fh</span>, <span class="re0">$len</span><span class="nu0">+1</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$toks</span>=<a href="http://www.php.net/explode"><span class="kw3">explode</span></a><span class="br0">&#40;</span><span class="st0">&#8216;:&#8217;</span>,<span class="re0">$msg</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$method</span> = <a href="http://www.php.net/array_shift"><span class="kw3">array_shift</span></a><span class="br0">&#40;</span><span class="re0">$toks</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">switch</span><span class="br0">&#40;</span><span class="re0">$method</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">&#8216;auth&#8217;</span>:</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/list"><span class="kw3">list</span></a><span class="br0">&#40;</span><span class="re0">$username</span>, <span class="re0">$server</span>, <span class="re0">$password</span><span class="br0">&#41;</span> = <span class="re0">$toks</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>@<span class="re0">$users</span><span class="br0">&#91;</span><span class="re0">$username</span><span class="br0">&#93;</span> == <span class="re0">$password</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <a href="http://www.php.net/pack"><span class="kw3">pack</span></a><span class="br0">&#40;</span><span class="st0">&quot;nn&quot;</span>, <span class="nu0">2</span>, <span class="nu0">1</span><span class="br0">&#41;</span>; <span class="co1">// ok</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="kw1">else</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <a href="http://www.php.net/pack"><span class="kw3">pack</span></a><span class="br0">&#40;</span><span class="st0">&quot;nn&quot;</span>, <span class="nu0">2</span>, <span class="nu0">0</span><span class="br0">&#41;</span>; <span class="co1">// fail</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">&#8216;isuser&#8217;</span>:</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/list"><span class="kw3">list</span></a><span class="br0">&#40;</span><span class="re0">$username</span>, <span class="re0">$server</span><span class="br0">&#41;</span> = <span class="re0">$toks</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$users</span><span class="br0">&#91;</span><span class="re0">$username</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <a href="http://www.php.net/pack"><span class="kw3">pack</span></a><span class="br0">&#40;</span><span class="st0">&quot;nn&quot;</span>, <span class="nu0">2</span>, <span class="nu0">1</span><span class="br0">&#41;</span>; <span class="co1">// yes</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="kw1">else</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <a href="http://www.php.net/pack"><span class="kw3">pack</span></a><span class="br0">&#40;</span><span class="st0">&quot;nn&quot;</span>, <span class="nu0">2</span>, <span class="nu0">0</span><span class="br0">&#41;</span>; <span class="co1">// nope</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">default</span>:</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <a href="http://www.php.net/pack"><span class="kw3">pack</span></a><span class="br0">&#40;</span><span class="st0">&quot;nn&quot;</span>, <span class="nu0">2</span>, <span class="nu0">0</span><span class="br0">&#41;</span>;<span class="co1">// fail</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span><span class="kw1">while</span><span class="br0">&#40;</span><span class="kw2">true</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p> <br/></p>
<p>I stripped down the ejabberd config to just load what I considered the bare essentials. Here is the modules section I&#8217;m testing with:</p>
<p>From ejabberd.cfg:<br />
<code>{modules,<br />
 [<br />
  {mod_caps,     []},<br />
  {mod_disco,    []},<br />
  {mod_roster,   []},<br />
  {mod_pubsub,   [ % requires mod_caps<br />
                  {access_createnode, pubsub_createnode},<br />
                  {plugins, ["default", "pep"]}<br />
                 ]},<br />
  {mod_mnesiaweb,     []},<br />
  {mod_thriftctl,     []}<br />
 ]}.</code><br/></p>
<p>mod_disco deals with discovery, so clients can find out what the server supports. mod_roster deals with rosters (buddy lists etc) using mnesia. mod_pubsub is enabled because I want to use <a href="http://xmpp.org/extensions/xep-0118.html">User Tune</a>, an extension that lets you broadcast the name of the song you are playing to all everyone in your roster. mod_caps provides <a href="http://xmpp.org/extensions/xep-0115.html">XEP-115</a> &#8211; an extension for broadcasting and dynamically discovering client, device, or generic entity capabilities. mod_caps is a requirement of mod_pubsub.</p>
<p>I&#8217;ve removed the module that allows users to register, although I made a few accounts first whilst testing. The last two modules, mod_mnesiaweb and mod_thriftctl are modules I wrote.</p>
<h2>mod_mnesiaweb</h2>
<p>To help figure out what&#8217;s going on inside of ejabberd, it&#8217;s useful to be able to easily browse the mnesia database. <a href="http://yaws.hyber.org/">Yaws</a> comes with an appmod that does this, called ymnesia. This ejabberd module will start yaws in embedded mode and run this appmod, enabling you to explore the mnesia database from a web browser.</p>
<p><i><b>Yaws observation:</b> yaws didn&#8217;t appear to build ymnesia by default, I edited the Makefile in src and added &#8220;ymnesia&#8221; to the module list. Also, if ./configure fails, the package you are probably missing is libpam0g-dev</i></p>
<p>mod_mnesiaweb:</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="co1">% Ejabberd module that runs yaws in embedded mode,</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">% and loads the ymnesia appmod for browsing mnesia.</span></div>
</li>
<li class="li1">
<div class="de1">-<span class="kw2">module</span><span class="br0">&#40;</span>mod_mnesiaweb<span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">-<span class="kw2">author</span><span class="br0">&#40;</span><span class="st0">&#8216;rj@last.fm&#8217;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">-include<span class="br0">&#40;</span><span class="st0">&quot;/usr/local/lib/yaws/include/yaws.hrl&quot;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">-<span class="kw2">behaviour</span><span class="br0">&#40;</span>gen_mod<span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">-<span class="kw2">export</span><span class="br0">&#40;</span><span class="br0">&#91;</span>start/<span class="nu0">2</span>, stop/<span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">start<span class="br0">&#40;</span>_<span class="re0">Host</span>, <span class="re0">Opts</span><span class="br0">&#41;</span> -&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">Port</span> = gen_mod:<span class="me2">get_opt</span><span class="br0">&#40;</span>port, <span class="re0">Opts</span>, <span class="nu0">8001</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; code:<span class="me2">add_path</span><span class="br0">&#40;</span><span class="st0">&quot;/usr/local/lib/yaws/ebin&quot;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; application:<span class="me2">set_env</span><span class="br0">&#40;</span>yaws, embedded, true<span class="br0">&#41;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; application:<span class="me2">start</span><span class="br0">&#40;</span>yaws<span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">GC</span> = yaws_config:<span class="me2">make_default_gconf</span><span class="br0">&#40;</span>false,<span class="st0">&quot;yawstest&quot;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">SC</span> = #sconf<span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; port = <span class="re0">Port</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; servername = <span class="st0">&quot;ejabnesia&quot;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">listen</span> = <span class="br0">&#123;</span><span class="nu0">0</span>,<span class="nu0">0</span>,<span class="nu0">0</span>,<span class="nu0">0</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; appmods = <span class="br0">&#91;</span><span class="br0">&#123;</span><span class="st0">&quot;showdb&quot;</span>, ymnesia<span class="br0">&#125;</span><span class="br0">&#93;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; docroot = <span class="st0">&quot;wwwroot&quot;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; yaws_api:<span class="me2">setconf</span><span class="br0">&#40;</span><span class="re0">GC</span>, <span class="br0">&#91;</span><span class="br0">&#91;</span><span class="re0">SC</span><span class="br0">&#93;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; ok.</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">stop<span class="br0">&#40;</span>_<span class="re0">Host</span><span class="br0">&#41;</span> -&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="me1">application</span>:<span class="me2">stop</span><span class="br0">&#40;</span>yaws<span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; ok.</div>
</li>
</ol>
</div>
<p><br/></p>
<p>To compile it:<br />
<code>erlc -pa ${EJAB_SRC} -I ${EJAB_SRC} mod_mnesiaweb.erl</code><br />
where EJAB_SRC is the ejabberd-2.X.X/src directory, after you&#8217;ve compiled from source (so the beams are there too).</p>
<p>Copy the resulting mod_mnesiaweb.beam to /var/lib/ejabberd/ebin so ejabberd finds it, and it should work. Hit up http://localhost:8001/showdb/ in your browser and you can explore the mnesia database.</p>
<p>Use the match syntax to filter tables. For example to find everyone in my roster, I use this in the input box next to roster:<br />
<code>{roster,{"RJ",'_', {'_','_',[]}}, '_','_','_','_','_','_','_','_'}</code><br/><br />
Not pretty, but it gets the job done. You can just view the entire table, copy a record then replace fields with &#8216;_&#8217; to build queries.</p>
<h2>mod_thriftctl</h2>
<p>Next up I wanted to try the Erlang <a href="http://incubator.apache.org/thrift/">Thrift</a> bindings (written by the folks at <a href="http://amiest-devblog.blogspot.com/2008/01/alternative-erlang-bindings-for-thrift.html">Amie St.</a>), and expose some useful functionality for controlling the server.</p>
<p>If you aren&#8217;t familiar with Thrift, I recommend reading about it first. In a nutshell, you write your API using an IDL (a .thrift file) and the thrift compiler creates client libraries, and server code in various different languages. It&#8217;s an RPC mechanism, and useful in a mixed environment.</p>
<p>mod_thriftctl.thrift:<br />
<code>#!/usr/local/bin/thrift -php -erl</p>
<p>struct JabberUser {<br />
    1: string name,<br />
    2: string server<br />
}</p>
<p>service Ejabthrift {<br />
    /* add ruser to roster of luser, and visa-versa. also routes presence to users if online  */<br />
    void add_friend(        1: JabberUser luser,<br />
                            2: JabberUser ruser<br />
                            ),</p>
<p>    /* remove ruser from luser's roster */<br />
    void remove_friend(    1: JabberUser luser, 2: JabberUser ruser ),</p>
<p>    /* make it look like fromuser sent a message to touser */<br />
    void spoof_message( 1: JabberUser fromuser, 2: JabberUser touser, 3: string message, 4: string subject ),<br />
    /* .. or a chat message */<br />
    void spoof_chat(    1: JabberUser fromuser, 2: JabberUser touser, 3: string message, 4: string thread ),</p>
<p>    /* sends PEP usertune message, see http://xmpp.org/extensions/xep-0118.html */<br />
    void publish_np ( 1: JabberUser fromuser, 2: string artist, 3: string album, 4: string track, 5: i32 tracklength, 6: i32 tracknum )<br />
}</code><br/></p>
<p>Run that .thrift file, and you get gen-php and gen-erl directories, with php client code, and erlang files needed to build a server. </p>
<p>Here&#8217;s the ejabberd module, which starts a thrift server:</p>
<p>mod_thriftctl:</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="co1">%</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">% A module to control ejabberd with a thrift interface.</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">%</span></div>
</li>
<li class="li1">
<div class="de1">-<span class="kw2">module</span><span class="br0">&#40;</span>mod_thriftctl<span class="br0">&#41;</span>.</div>
</li>
<li class="li2">
<div class="de2">-<span class="kw2">author</span><span class="br0">&#40;</span><span class="st0">&#8216;rj@last.fm&#8217;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">% ejabberd headers:</span></div>
</li>
<li class="li1">
<div class="de1">-include<span class="br0">&#40;</span><span class="st0">&quot;ejabberd.hrl&quot;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">-include<span class="br0">&#40;</span><span class="st0">&quot;mod_roster.hrl&quot;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li2">
<div class="de2">-include<span class="br0">&#40;</span><span class="st0">&quot;jlib.hrl&quot;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">% thrift server headers:</span></div>
</li>
<li class="li1">
<div class="de1">-include<span class="br0">&#40;</span><span class="st0">&quot;thrift.hrl&quot;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">-include<span class="br0">&#40;</span><span class="st0">&quot;transport/tSocket.hrl&quot;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li2">
<div class="de2">-include<span class="br0">&#40;</span><span class="st0">&quot;protocol/tBinaryProtocol.hrl&quot;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">-include<span class="br0">&#40;</span><span class="st0">&quot;server/tErlServer.hrl&quot;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">-include<span class="br0">&#40;</span><span class="st0">&quot;transport/tErlAcceptor.hrl&quot;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">% we are an ejabberd module:</span></div>
</li>
<li class="li2">
<div class="de2">-<span class="kw2">behaviour</span><span class="br0">&#40;</span>gen_mod<span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">-<span class="kw2">export</span><span class="br0">&#40;</span><span class="br0">&#91;</span>start/<span class="nu0">2</span>, stop/<span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">% our thrift service:</span></div>
</li>
<li class="li1">
<div class="de1">-include<span class="br0">&#40;</span><span class="st0">&quot;ejabthrift_thrift.hrl&quot;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li2">
<div class="de2">-include<span class="br0">&#40;</span><span class="st0">&quot;mod_thriftctl_types.hrl&quot;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">-<span class="kw2">export</span><span class="br0">&#40;</span><span class="br0">&#91;</span> &nbsp; add_friend/<span class="nu0">2</span>, remove_friend/<span class="nu0">2</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; spoof_message/<span class="nu0">4</span>, spoof_chat/<span class="nu0">4</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; publish_np/<span class="nu0">6</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#93;</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">% convert thrift Jabberuser into ejabberd jid</span></div>
</li>
<li class="li1">
<div class="de1">ju2jid<span class="br0">&#40;</span><span class="re0">Jabberuser</span><span class="br0">&#41;</span> when is_record<span class="br0">&#40;</span><span class="re0">Jabberuser</span>, jabber<span class="re0">User</span><span class="br0">&#41;</span> -&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; #jid<span class="br0">&#123;</span> user=<span class="re0">Jabberuser</span>#jabber<span class="re0">User</span>.name, server=<span class="re0">Jabberuser</span>#jabber<span class="re0">User</span>.server, resource=<span class="st0">&quot;&quot;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; luser=<span class="re0">Jabberuser</span>#jabber<span class="re0">User</span>.name, lserver=<span class="re0">Jabberuser</span>#jabber<span class="re0">User</span>.server, lresource=<span class="st0">&quot;&quot;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">spoof_message<span class="br0">&#40;</span> <span class="re0">FromU</span>, <span class="re0">ToU</span>, <span class="re0">Msg</span>, <span class="re0">Subject</span> <span class="br0">&#41;</span> -&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">F</span> = ju2jid<span class="br0">&#40;</span><span class="re0">FromU</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">T</span> = ju2jid<span class="br0">&#40;</span><span class="re0">ToU</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">XmlBody</span> = <span class="br0">&#123;</span>xmlelement, <span class="st0">&quot;message&quot;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#91;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><span class="st0">&quot;from&quot;</span>, jlib:<span class="me2">jid_to_string</span><span class="br0">&#40;</span><span class="re0">F</span><span class="br0">&#41;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><span class="st0">&quot;to&quot;</span>, jlib:<span class="me2">jid_to_string</span><span class="br0">&#40;</span><span class="re0">T</span><span class="br0">&#41;</span><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#93;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#91;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlelement, <span class="st0">&quot;subject&quot;</span>, <span class="br0">&#91;</span><span class="br0">&#93;</span>, <span class="br0">&#91;</span><span class="br0">&#123;</span>xmlcdata, <span class="re0">Subject</span><span class="br0">&#125;</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlelement, <span class="st0">&quot;body&quot;</span>, <span class="br0">&#91;</span><span class="br0">&#93;</span>, <span class="br0">&#91;</span><span class="br0">&#123;</span>xmlcdata, <span class="re0">Msg</span><span class="br0">&#125;</span><span class="br0">&#93;</span><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#93;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; ejabberd_router:<span class="me2">route</span><span class="br0">&#40;</span><span class="re0">F</span>, <span class="re0">T</span>, <span class="re0">XmlBody</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">spoof_chat<span class="br0">&#40;</span> <span class="re0">FromU</span>, <span class="re0">ToU</span>, <span class="re0">Msg</span>, <span class="re0">Thread</span> <span class="br0">&#41;</span> -&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">F</span> = ju2jid<span class="br0">&#40;</span><span class="re0">FromU</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">T</span> = ju2jid<span class="br0">&#40;</span><span class="re0">ToU</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">XmlBody</span> = <span class="br0">&#123;</span>xmlelement, <span class="st0">&quot;message&quot;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#91;</span><span class="br0">&#123;</span><span class="st0">&quot;type&quot;</span>, <span class="st0">&quot;chat&quot;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><span class="st0">&quot;from&quot;</span>, jlib:<span class="me2">jid_to_string</span><span class="br0">&#40;</span><span class="re0">F</span><span class="br0">&#41;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><span class="st0">&quot;to&quot;</span>, jlib:<span class="me2">jid_to_string</span><span class="br0">&#40;</span><span class="re0">T</span><span class="br0">&#41;</span><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#93;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#91;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlelement, <span class="st0">&quot;thread&quot;</span>, <span class="br0">&#91;</span><span class="br0">&#93;</span>, <span class="br0">&#91;</span><span class="br0">&#123;</span>xmlcdata, <span class="re0">Thread</span><span class="br0">&#125;</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlelement, <span class="st0">&quot;body&quot;</span>, <span class="br0">&#91;</span><span class="br0">&#93;</span>, <span class="br0">&#91;</span><span class="br0">&#123;</span>xmlcdata, <span class="re0">Msg</span><span class="br0">&#125;</span><span class="br0">&#93;</span><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#93;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; ejabberd_router:<span class="me2">route</span><span class="br0">&#40;</span><span class="re0">F</span>, <span class="re0">T</span>, <span class="re0">XmlBody</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">publish_np<span class="br0">&#40;</span> <span class="re0">FromU</span>, <span class="re0">ArtistS</span>, <span class="re0">AlbumS</span>, <span class="re0">TrackS</span>, <span class="re0">LengthI</span>, <span class="re0">TrackNumI</span> <span class="br0">&#41;</span> -&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">From</span> = ju2jid<span class="br0">&#40;</span><span class="re0">FromU</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">% The usertune message must contain binaries, not strings or ints</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">FromStr</span> &nbsp; &nbsp; = jlib:<span class="me2">jid_to_string</span><span class="br0">&#40;</span><span class="re0">From</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">Artist</span> &nbsp; &nbsp; &nbsp;= list_to_binary<span class="br0">&#40;</span><span class="re0">ArtistS</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">Album</span> &nbsp; &nbsp; &nbsp; = list_to_binary<span class="br0">&#40;</span><span class="re0">AlbumS</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">Track</span> &nbsp; &nbsp; &nbsp; = list_to_binary<span class="br0">&#40;</span><span class="re0">TrackS</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">Length</span> &nbsp; &nbsp; &nbsp;= list_to_binary<span class="br0">&#40;</span>io_lib:<span class="kw3">format</span><span class="br0">&#40;</span><span class="st0">&quot;~w&quot;</span>,<span class="br0">&#91;</span><span class="re0">LengthI</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">TrackNum</span> &nbsp; &nbsp;= list_to_binary<span class="br0">&#40;</span>io_lib:<span class="kw3">format</span><span class="br0">&#40;</span><span class="st0">&quot;~w&quot;</span>,<span class="br0">&#91;</span><span class="re0">TrackNumI</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">Xml</span> = <span class="br0">&#123;</span>xmlelement,<span class="st0">&quot;iq&quot;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="br0">&#123;</span><span class="st0">&quot;from&quot;</span>, <span class="re0">FromStr</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span><span class="st0">&quot;type&quot;</span>,<span class="st0">&quot;set&quot;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span><span class="st0">&quot;id&quot;</span>,<span class="st0">&quot;pub1&quot;</span><span class="br0">&#125;</span><span class="br0">&#93;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="br0">&#123;</span>xmlcdata,&lt;&lt;<span class="st0">&quot;<span class="es0">\n</span> &nbsp;&quot;</span>&gt;&gt;<span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlelement,<span class="st0">&quot;pubsub&quot;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="br0">&#123;</span><span class="st0">&quot;xmlns&quot;</span>,<span class="st0">&quot;http://jabber.org/protocol/pubsub&quot;</span><span class="br0">&#125;</span><span class="br0">&#93;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="br0">&#123;</span>xmlcdata,&lt;&lt;<span class="st0">&quot;<span class="es0">\n</span> &nbsp; &nbsp;&quot;</span>&gt;&gt;<span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlelement,<span class="st0">&quot;publish&quot;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="br0">&#123;</span><span class="st0">&quot;node&quot;</span>,<span class="st0">&quot;http://jabber.org/protocol/tune&quot;</span><span class="br0">&#125;</span><span class="br0">&#93;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="br0">&#123;</span>xmlcdata,&lt;&lt;<span class="st0">&quot;<span class="es0">\n</span> &nbsp; &nbsp; &nbsp;&quot;</span>&gt;&gt;<span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlelement,<span class="st0">&quot;item&quot;</span>,<span class="br0">&#91;</span><span class="br0">&#93;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="br0">&#123;</span>xmlcdata,&lt;&lt;<span class="st0">&quot;<span class="es0">\n</span> &nbsp; &nbsp; &nbsp; &nbsp;&quot;</span>&gt;&gt;<span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlelement,<span class="st0">&quot;tune&quot;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="br0">&#123;</span><span class="st0">&quot;xmlns&quot;</span>,<span class="st0">&quot;http://jabber.org/protocol/tune&quot;</span><span class="br0">&#125;</span><span class="br0">&#93;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="br0">&#123;</span>xmlcdata,&lt;&lt;<span class="st0">&quot;<span class="es0">\n</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;</span>&gt;&gt;<span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlelement,<span class="st0">&quot;artist&quot;</span>,<span class="br0">&#91;</span><span class="br0">&#93;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="br0">&#123;</span>xmlcdata, <span class="re0">Artist</span><span class="br0">&#125;</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlcdata,&lt;&lt;<span class="st0">&quot;<span class="es0">\n</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;</span>&gt;&gt;<span class="br0">&#125;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlelement,<span class="st0">&quot;length&quot;</span>,<span class="br0">&#91;</span><span class="br0">&#93;</span>,<span class="br0">&#91;</span><span class="br0">&#123;</span>xmlcdata, <span class="re0">Length</span><span class="br0">&#125;</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlcdata,&lt;&lt;<span class="st0">&quot;<span class="es0">\n</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;</span>&gt;&gt;<span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlelement,<span class="st0">&quot;source&quot;</span>,<span class="br0">&#91;</span><span class="br0">&#93;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="br0">&#123;</span>xmlcdata, <span class="re0">Album</span><span class="br0">&#125;</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlcdata,&lt;&lt;<span class="st0">&quot;<span class="es0">\n</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;</span>&gt;&gt;<span class="br0">&#125;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlelement,<span class="st0">&quot;title&quot;</span>,<span class="br0">&#91;</span><span class="br0">&#93;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="br0">&#123;</span>xmlcdata, <span class="re0">Track</span><span class="br0">&#125;</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlcdata,&lt;&lt;<span class="st0">&quot;<span class="es0">\n</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;</span>&gt;&gt;<span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlelement,<span class="st0">&quot;track&quot;</span>,<span class="br0">&#91;</span><span class="br0">&#93;</span>,<span class="br0">&#91;</span><span class="br0">&#123;</span>xmlcdata, <span class="re0">TrackNum</span><span class="br0">&#125;</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlcdata,&lt;&lt;<span class="st0">&quot;<span class="es0">\n</span> &nbsp; &nbsp; &nbsp; &nbsp;&quot;</span>&gt;&gt;<span class="br0">&#125;</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlcdata,&lt;&lt;<span class="st0">&quot;<span class="es0">\n</span> &nbsp; &nbsp; &nbsp;&quot;</span>&gt;&gt;<span class="br0">&#125;</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlcdata,&lt;&lt;<span class="st0">&quot;<span class="es0">\n</span> &nbsp; &nbsp;&quot;</span>&gt;&gt;<span class="br0">&#125;</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlcdata,&lt;&lt;<span class="st0">&quot;<span class="es0">\n</span> &nbsp;&quot;</span>&gt;&gt;<span class="br0">&#125;</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span>xmlcdata,&lt;&lt;<span class="st0">&quot;<span class="es0">\n</span>&quot;</span>&gt;&gt;<span class="br0">&#125;</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">% PEP means you act as a pubsub node yourself,</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="co1">% so it&#8217;s addressed to yourself and is broadcast to your friends automatically:</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; ejabberd_router:<span class="me2">route</span><span class="br0">&#40;</span><span class="re0">From</span>, <span class="re0">From</span>, <span class="re0">Xml</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; ok.</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">% adds bi-directional friend relationship immediately for both users.</span></div>
</li>
<li class="li2">
<div class="de2">add_friend<span class="br0">&#40;</span> &nbsp; &nbsp; #jabber<span class="re0">User</span><span class="br0">&#123;</span>name=<span class="re0">LU</span>, server=<span class="re0">LS</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #jabber<span class="re0">User</span><span class="br0">&#123;</span>name=<span class="re0">RU</span>, server=<span class="re0">RS</span><span class="br0">&#125;</span><span class="br0">&#41;</span> -&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">AskMessage</span> = <span class="st0">&quot;&quot;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">Group</span> = <span class="st0">&quot;&quot;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">Subtype</span> = both,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; subscribe<span class="br0">&#40;</span><span class="re0">LU</span>, <span class="re0">LS</span>, <span class="re0">RU</span>, <span class="re0">RS</span>, <span class="re0">RU</span>, <span class="re0">Group</span>, <span class="re0">Subtype</span>, <span class="re0">AskMessage</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; subscribe<span class="br0">&#40;</span><span class="re0">RU</span>, <span class="re0">RS</span>, <span class="re0">LU</span>, <span class="re0">LS</span>, <span class="re0">LU</span>, <span class="re0">Group</span>, <span class="re0">Subtype</span>, <span class="re0">AskMessage</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; route_rosteritem<span class="br0">&#40;</span><span class="re0">LU</span>, <span class="re0">LS</span>, <span class="re0">RU</span>, <span class="re0">RS</span>, <span class="re0">RU</span>, <span class="re0">Group</span>, <span class="re0">Subtype</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; route_rosteritem<span class="br0">&#40;</span><span class="re0">RU</span>, <span class="re0">RS</span>, <span class="re0">LU</span>, <span class="re0">LS</span>, <span class="re0">LU</span>, <span class="re0">Group</span>, <span class="re0">Subtype</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; ok.</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">remove_friend<span class="br0">&#40;</span> #jabber<span class="re0">User</span><span class="br0">&#123;</span>name=<span class="re0">LU</span>, server=<span class="re0">LS</span><span class="br0">&#125;</span>, #jabber<span class="re0">User</span><span class="br0">&#123;</span>name=<span class="re0">RU</span>, server=<span class="re0">RS</span><span class="br0">&#125;</span> <span class="br0">&#41;</span> -&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="me1">unsubscribe</span><span class="br0">&#40;</span><span class="re0">LU</span>, <span class="re0">LS</span>, <span class="re0">RU</span>, <span class="re0">RS</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; unsubscribe<span class="br0">&#40;</span><span class="re0">RU</span>, <span class="re0">RS</span>, <span class="re0">LU</span>, <span class="re0">LS</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; route_rosteritem<span class="br0">&#40;</span><span class="re0">LU</span>, <span class="re0">LS</span>, <span class="re0">RU</span>, <span class="re0">RS</span>, <span class="st0">&quot;&quot;</span>, <span class="st0">&quot;&quot;</span>, <span class="st0">&quot;remove&quot;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; route_rosteritem<span class="br0">&#40;</span><span class="re0">RU</span>, <span class="re0">RS</span>, <span class="re0">LU</span>, <span class="re0">LS</span>, <span class="st0">&quot;&quot;</span>, <span class="st0">&quot;&quot;</span>, <span class="st0">&quot;remove&quot;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; ok.</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">unsubscribe<span class="br0">&#40;</span><span class="re0">LocalUser</span>, <span class="re0">LocalServer</span>, <span class="re0">RemoteUser</span>, <span class="re0">RemoteServer</span><span class="br0">&#41;</span> -&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">Key</span> = <span class="br0">&#123;</span><span class="br0">&#123;</span><span class="re0">LocalUser</span>,<span class="re0">LocalServer</span>,<span class="br0">&#123;</span><span class="re0">RemoteUser</span>,<span class="re0">RemoteServer</span>,<span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#125;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span><span class="re0">LocalUser</span>,<span class="re0">LocalServer</span><span class="br0">&#125;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; mnesia:<span class="me2">transaction</span><span class="br0">&#40;</span>fun<span class="br0">&#40;</span><span class="br0">&#41;</span> -&gt; <span class="me1">mnesia</span>:<span class="me2">delete</span><span class="br0">&#40;</span>roster, <span class="re0">Key</span>, write<span class="br0">&#41;</span> <span class="kw1">end</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">route_rosteritem<span class="br0">&#40;</span><span class="re0">LocalUser</span>, <span class="re0">LocalServer</span>, <span class="re0">RemoteUser</span>, <span class="re0">RemoteServer</span>, <span class="re0">Nick</span>, <span class="re0">Group</span>, <span class="re0">Subscription</span><span class="br0">&#41;</span> -&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">LJID</span> = jlib:<span class="me2">make_jid</span><span class="br0">&#40;</span><span class="re0">LocalUser</span>, <span class="re0">LocalServer</span>, <span class="st0">&quot;&quot;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">RJID</span> = jlib:<span class="me2">make_jid</span><span class="br0">&#40;</span><span class="re0">RemoteUser</span>, <span class="re0">RemoteServer</span>, <span class="st0">&quot;&quot;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">ToS</span> = jlib:<span class="me2">jid_to_string</span><span class="br0">&#40;</span><span class="re0">LJID</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">ItemJIDS</span> = jlib:<span class="me2">jid_to_string</span><span class="br0">&#40;</span><span class="re0">RJID</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">GroupXML</span> = <span class="br0">&#123;</span>xmlelement, <span class="st0">&quot;group&quot;</span>, <span class="br0">&#91;</span><span class="br0">&#93;</span>, <span class="br0">&#91;</span><span class="br0">&#123;</span>xmlcdata, <span class="re0">Group</span><span class="br0">&#125;</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">Item</span> = <span class="br0">&#123;</span>xmlelement, <span class="st0">&quot;item&quot;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="br0">&#123;</span><span class="st0">&quot;jid&quot;</span>, <span class="re0">ItemJIDS</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span><span class="st0">&quot;name&quot;</span>, <span class="re0">Nick</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#123;</span><span class="st0">&quot;subscription&quot;</span>, <span class="re0">Subscription</span><span class="br0">&#125;</span><span class="br0">&#93;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="re0">GroupXML</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">Query</span> = <span class="br0">&#123;</span>xmlelement, <span class="st0">&quot;query&quot;</span>, <span class="br0">&#91;</span><span class="br0">&#123;</span><span class="st0">&quot;xmlns&quot;</span>, ?<span class="re0">NS_ROSTER</span><span class="br0">&#125;</span><span class="br0">&#93;</span>, <span class="br0">&#91;</span><span class="re0">Item</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">Packet</span> = <span class="br0">&#123;</span>xmlelement, <span class="st0">&quot;iq&quot;</span>, <span class="br0">&#91;</span><span class="br0">&#123;</span><span class="st0">&quot;type&quot;</span>, <span class="st0">&quot;set&quot;</span><span class="br0">&#125;</span>, <span class="br0">&#123;</span><span class="st0">&quot;to&quot;</span>, <span class="re0">ToS</span><span class="br0">&#125;</span><span class="br0">&#93;</span>, <span class="br0">&#91;</span><span class="re0">Query</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; ejabberd_router:<span class="me2">route</span><span class="br0">&#40;</span><span class="re0">LJID</span>, <span class="re0">LJID</span>, <span class="re0">Packet</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">subscribe<span class="br0">&#40;</span><span class="re0">LocalUser</span>, <span class="re0">LocalServer</span>, <span class="re0">RemoteUser</span>, <span class="re0">RemoteServer</span>, <span class="re0">Nick</span>, <span class="re0">Group</span>, <span class="re0">Subscription</span>, <span class="re0">Xattrs</span><span class="br0">&#41;</span> -&gt;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">R</span> = #roster<span class="br0">&#123;</span>usj = <span class="br0">&#123;</span><span class="re0">LocalUser</span>,<span class="re0">LocalServer</span>,<span class="br0">&#123;</span><span class="re0">RemoteUser</span>,<span class="re0">RemoteServer</span>,<span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#125;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; us = <span class="br0">&#123;</span><span class="re0">LocalUser</span>,<span class="re0">LocalServer</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jid = <span class="br0">&#123;</span><span class="re0">RemoteUser</span>,<span class="re0">RemoteServer</span>,<span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#125;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name = <span class="re0">Nick</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; subscription = <span class="re0">Subscription</span>, <span class="co1">% none, to=you see him, from=he sees you, both</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ask = none, <span class="co1">% out=send request, in=somebody requests you, none</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; groups = <span class="br0">&#91;</span><span class="re0">Group</span><span class="br0">&#93;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; askmessage = <span class="re0">Xattrs</span>, <span class="co1">% example: [{&quot;category&quot;,&quot;conference&quot;}]</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; xs = <span class="br0">&#91;</span><span class="br0">&#93;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#125;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; mnesia:<span class="me2">transaction</span><span class="br0">&#40;</span>fun<span class="br0">&#40;</span><span class="br0">&#41;</span> -&gt; <span class="me1">mnesia</span>:<span class="me2">write</span><span class="br0">&#40;</span><span class="re0">R</span><span class="br0">&#41;</span> <span class="kw1">end</span><span class="br0">&#41;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">start<span class="br0">&#40;</span><span class="re0">Host</span>, <span class="re0">Opts</span><span class="br0">&#41;</span> -&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; ?<span class="re0">INFO</span><span class="br0">&#40;</span><span class="st0">&quot;mod_ejabthrift start().&quot;</span>,<span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">%% get options</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">Port</span> = gen_mod:<span class="me2">get_opt</span><span class="br0">&#40;</span>port, <span class="re0">Opts</span>, <span class="nu0">9000</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; spawn<span class="br0">&#40;</span>fun<span class="br0">&#40;</span><span class="br0">&#41;</span>-&gt; <span class="me1">thrift</span>:<span class="me2">start</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw1">end</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; ?<span class="re0">INFO</span><span class="br0">&#40;</span><span class="st0">&quot;mod_ejabthrift thrift:start().&quot;</span>,<span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">Handler</span> &nbsp; = ?<span class="re0">MODULE</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">Processor</span> = ejabthrift_thrift,</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">TF</span> = t<span class="re0">BufferedTransportFactory</span>:<span class="me2">new</span><span class="br0">&#40;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">PF</span> = t<span class="re0">BinaryProtocolFactory</span>:<span class="me2">new</span><span class="br0">&#40;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">ServerTransport</span> = t<span class="re0">ErlAcceptor</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">ServerFlavor</span> &nbsp; &nbsp;= t<span class="re0">ErlServer</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">Server</span> = oop:<span class="me2">start_new</span><span class="br0">&#40;</span><span class="re0">ServerFlavor</span>, <span class="br0">&#91;</span><span class="re0">Port</span>, <span class="re0">Handler</span>, <span class="re0">Processor</span>, <span class="re0">ServerTransport</span>, <span class="re0">TF</span>, <span class="re0">PF</span><span class="br0">&#93;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">case</span> ?<span class="re0">R0</span><span class="br0">&#40;</span><span class="re0">Server</span>, effectful_serve<span class="br0">&#41;</span> <span class="kw1">of</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; ok &nbsp; &nbsp;-&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; ?<span class="re0">INFO</span><span class="br0">&#40;</span><span class="st0">&quot;mod_ejabthrift: Thrift server (~s) listening on port ~w&quot;</span>,<span class="br0">&#91;</span><span class="re0">Host</span>, <span class="re0">Port</span><span class="br0">&#93;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">% put Server into process dictionary (needed for clean stop)</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; put<span class="br0">&#40;</span>thrift_server_reference, <span class="re0">Server</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; ok;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">Error</span> -&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; ?<span class="re0">ERROR_MSG</span><span class="br0">&#40;</span><span class="st0">&quot;mod_ejabthrift: Error starting thrift server: ~w&quot;</span>, <span class="br0">&#91;</span><span class="re0">Error</span><span class="br0">&#93;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">Error</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw1">end</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">stop<span class="br0">&#40;</span>_<span class="re0">Host</span><span class="br0">&#41;</span> -&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; ?<span class="re0">C0</span><span class="br0">&#40;</span>get<span class="br0">&#40;</span>thrift_server_reference<span class="br0">&#41;</span>, stop<span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; ok.</div>
</li>
</ol>
</div>
<p><br/></p>
<p>To build, first build the gen-erl code:</p>
<p><code>erlc -pa ${EJAB_SRC} -I ${EJAB_SRC} -I ${ERL_THRIFT}/include -I ./gen-erl -o ./gen-erl ./gen-erl/*.erl</code></p>
<p>Where ERL_THRIFT is the lib/erl directory from the amiethrift code, git://repo.or.cz/amiethrift.git</p>
<p>Then compile the module:</p>
<p><code>erlc -pa ${EJAB_SRC} -I ${EJAB_SRC} -I ${ERL_THRIFT}/include -I ./gen-erl *.erl</code></p>
<p>To install, copy all the beam files to the ejabberd ebin dir:</p>
<p><code>sudo cp *.beam gen-erl/*.beam /var/lib/ejabberd/ebin/</code></p>
<p>This is inspired by mod_xmlrpc, which is in ejabberd-modules. As you can see from the start function, that&#8217;s what it takes to start a thrift server. It&#8217;s now trivial to call into ejabberd from other languages. For example, if you started listening to a song using a flash player on the website, a php webservice could make a user tune announcement on your behalf, or spoof messages from you boasting how much you love listening to Paris Hilton. </p>
<p>If anyone knows where I can read about the ejabberd architecture / design, so I don&#8217;t have to piece it all together myself, please let me know.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.metabrew.com/article/getting-to-know-ejabberd-and-writing-modules//feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>On bulk loading data into Mnesia</title>
		<link>http://www.metabrew.com/article/on-bulk-loading-data-into-mnesia/</link>
		<comments>http://www.metabrew.com/article/on-bulk-loading-data-into-mnesia/#comments</comments>
		<pubDate>Mon, 13 Oct 2008 20:08:49 +0000</pubDate>
		<dc:creator>RJ</dc:creator>
				<category><![CDATA[hacks]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[erlang]]></category>
		<category><![CDATA[mnesia]]></category>

		<guid isPermaLink="false">http://www.metabrew.com/?p=82</guid>
		<description><![CDATA[Consider this a work-in-progress; I will update this post if I find a &#8216;better&#8217; way to do fast bulk loading The time has come to replace my ets-based storage backend with something non-volatile. I considered a dets/ets hybrid, but I really need this to be replicated to at least a second node for HA / [...]]]></description>
			<content:encoded><![CDATA[<p><i>Consider this a work-in-progress; I will update this post if I find a &#8216;better&#8217; way to do fast bulk loading</i></p>
<p>The time has come to replace my ets-based storage backend with something non-volatile. I considered a dets/ets hybrid, but I really need this to be replicated to at least a second node for HA / failover. Mnesia beckoned. </p>
<p>The problem:</p>
<ul>
<li>15 million [fairly simple] records</li>
<li>1 Mnesia table: bag, disc_copies, just 1 node, 1 additional index</li>
<li>Hardware is a quad-core 2GHz CPU, 16GB Ram, 8x 74Gig 15k rpm scsi disks in RAID-6</li>
<li>Takes ages* to load and spews a load of &#8220;Mnesia is overloaded&#8221; warnings</li>
</ul>
<p><b>* My definition of &#8216;takes ages&#8217;:</b> Much longer than PostgreSQL <code>\copy</code> or MySQL <code>LOAD DATA INFILE</code></p>
<p>At this point all I want is a quick way to bulk-load some data into a disc_copies table on a single node, so I can get on with running some tests.</p>
<p>Here is the table creation code:<br />
<code>    mnesia:create_table(subscription,<br />
            [<br />
                {disc_copies, [node()]},<br />
                {attributes, record_info(fields, subscription)},<br />
                {index, [subscribee]}, %index subscribee too<br />
                {type, bag}<br />
            ]<br />
            )</code><br />
The <code>subscription</code> record is fairly simple:<br />
<code>{subscription, subscriber={resource, user, 123}, subscribee={resource, artist, 456}}</code></p>
<p>I&#8217;m starting erlang like so:<br />
<code>erl +A 128 -mnesia dir '"/home/erlang/mnesia_dir"' -boot start_sasl</code></p>
<p>The interesting thing there is really the <code>+A 128</code> &#8211; this spreads the cpu load better between the 4 cores.</p>
<h3>Attempt 0) &#8216;by the book&#8217; one transaction to rule them all</h3>
<p>Something like this:<br />
<code>mnesia:transaction(fun()-> [ mnesia:write(S) || S <- Subs ] end)</code></p>
<p>Time taken: <b>Too long, I gave up after 12 hours</b><br />
Number of &#8220;Mnesia overloaded&#8221; warnings: <b>lots</b><br />
Conclusion: <b>Must be a better way</b><br />
TODO: actually run this test and time it.</p>
<h3>Attempt 1) dirty_write</h3>
<p>There isn&#8217;t really any need to do this in a transaction, so I tried dirty_write.<br />
<code>[ mnesia:dirty_write(S) || S <- Subs ]</code></p>
<p>And here&#8217;s the warning in full:<br />
<code>=ERROR REPORT==== 13-Oct-2008::16:53:57 ===<br />
Mnesia('mynode@myhost'): ** WARNING ** Mnesia is overloaded: {dump_log,<br />
                                                                       write_threshold}</code></p>
<p>Time taken: <b>890 secs</b><br />
Number of &#8220;Mnesia overloaded&#8221; warnings: <b>lots</b><br />
Conclusion: <b>Workable, but nothing to boast about. Those warnings are annoying</b></p>
<h3>Attempt 2) dirty_write, defer index creation</h3>
<p>A common trick with traditional RDBMS would be to bulk load the data into the table and add the indexes afterwards. In some scenarios you can avoid costly incremental index update operations. If you are doing this in one gigantic transaction it shouldn&#8217;t matter, and I&#8217;m not really sure how mnesia works under the hood (something I plan to rectify if I end up using it for real).<br />
I tried a similar approach by commenting out the <code>{index, [subscribee]}</code> line above, doing the load, then using <code>mnesia:add_table_index(subscriber, subscribee)</code> afterwards to add the index once all the data was loaded. Note that mnesia was still building the primary index on the fly, but that can&#8217;t be helped.<br />
Time taken: <b>883 secs</b> (679s load + 204s index creation)<br />
Number of &#8220;Mnesia overloaded&#8221; warnings: <b>lots</b><br />
Conclusion: <b>Insignificant, meh</b></p>
<h3>Attempt 3) mnesia:ets() trickery</h3>
<p>This is slightly perverted, but I tried it because I was suspicious that incrementally updating the on-disk data wasn&#8217;t especially optimal. The idea is to make a ram_only table and use the mnesia:ets() function to write directly to the ets table (doesn&#8217;t get much faster than ets). The table can then be converted to disc_copies. There are caveats &#8211; to quote The Fine Manual:</p>
<blockquote><p>Call the Fun in a raw context which is not protected by a transaction. The Mnesia function call is performed in the Fun are performed directly on the local ets tables on the assumption that the local storage type is ram_copies and the tables are not replicated to other nodes. Subscriptions are not triggered and checkpoints are not updated, but it is extremely fast.</p></blockquote>
<p>I can live with that. I don&#8217;t mind if replication takes a while to setup when I put this into production &#8211; I&#8217;ll gladly take any optimisations I can get at this stage (testing/development).</p>
<p>Loading a list of <code>subscriptions</code> looks like this:<br />
<code>mnesia:ets(fun()-> [mnesia:dirty_write(S) || S <- Subs] end).</code><br />
And to convert this into disc_copies once data is loaded in:<br />
<code>mnesia:change_table_copy_type(subscription, node(), disc_copies).</code></p>
<p>Time taken: <b>745 secs</b> (699s load + 46s convert to disc_copies)<br />
Number of &#8220;Mnesia overloaded&#8221; warnings: <b>none!</b><br />
Conclusion: <b>Fastest yet, bit hacky</b></p>
<h2>Summary</h2>
<p>At least the ets() trick doesn&#8217;t spew a million warnings. I also need to examine the output of <code>mnesia:dump_to_textfile</code> and see if loading data from that format is any faster.</p>
<p>TODO:</p>
<ul>
<li>Examine / test using the dum_to_textfile method</li>
<li>Run full transactional load and time it</li>
<li>Try similar thing with PostgreSQL</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.metabrew.com/article/on-bulk-loading-data-into-mnesia//feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>
