Ejabberd用のモジュールを書く

ejabberd XMPPサーバーの非標準機能が必要な場合、通常のツールを使用して設定する方法がわからず、これに適したモジュールが見つからない場合は、このモジュールを自分で作成できます。



そのため、当局がジャバーでのアイドルチャットに関する戦争を宣言したとき、一部のユーザーは他のユーザーとチャットすることを禁止する必要がありましたが、3番目のユーザーは許可する必要がありました。 そして、アクセスリストを使用してこれを設定できるという疑いはまだありますが、使いやすいモジュールを作成することにしました。 このモジュールは、ストーリーの例として役立ちます。



準備する



最初に、少なくとも少しのプログラミング言語アーランを学ぶ必要があります。 私はRSDN Magazineの記事翻訳公式文書を使用しました

その後、コンピューターを準備してモジュールを構築する必要があります。 インストールされたerlangとejabberdに加えて、いくつかのライブラリをモジュールに接続するためにソースコードが必要になります。



動作中のモジュールを確認するには、次のものが必要です。

  1. コンパイルします。

    $ erlc mod_restrictions.erl
          
          



  2. 結果のバイナリをejabberdのフォルダーに移動します。

     $ mv mod_restrictions.beam /usr/lib/ejabberd/ebin/
          
          



  3. 新しい(更新された)モジュールをダウンロードします。 これを行うには、単にejabberdを再起動します。

     $ service ejabberd restart
          
          



    そして、例えば、jajabberd管理エリアで、 その場モジュールを更新できます( ノード->あなたのノード->更新
(Ubuntu 11.04のコマンド)



コンパイラは次のように記述できます。



 ./mod_restrictions.erl:5: Warning: behaviour gen_mod undefined
      
      





それは怖くない、すべてが動作します。 他にエラーや警告がある場合は、それらに対処する必要があります。



ejabber config(ファイル/etc/ejabberd/ejabberd.cfg)のモジュールを接続するには、モジュールのリストに行を追加します( {modules,[



)の後に:



 {mod_restrictions, []}
      
      





スケルトン



Ejabberdモジュールはgen_modインターフェースを継承する必要があります。 この動作には、 start / 2stop / 1の 2つの関数が必要です。これらはそれぞれ、モジュールの起動と停止時に呼び出されます。 mod_restrictions.erlファイルに次のコードを記述します。



 -module(mod_restrictions). -behavior(gen_mod). -export([start/2, stop/1]). start(_Host, _Opts) ->  ok. stop(_Host) ->  ok.
      
      





ここにあります:

  1. モジュールの名前を指定します(.erlのないファイルの名前のようにする必要があります)。
  2. gen_modの動作を継承します。
  3. 関数の開始(2つの引数)と停止(1つの引数)は、モジュールの外部からアクセスできると言います。
  4. 関数を書きます。 引数名の下のスペースは、これらの引数が使用されていないことをErlangに伝えます。
  5. OKを返す


ログに書き込みます



ログにイベントを記録するには(たとえば、モジュールの開始と停止) 、? INFO_MSGマクロを使用できます。



 -module(mod_restrictions). -behavior(gen_mod). -include("ejabberd.hrl"). -export([start/2, stop/1]). start(Host, _Opts) ->  ?INFO_MSG("mod_restrictions   ~p", [Host]),  ok. stop(Host) ->  ?INFO_MSG("mod_restrictions   ~p", [Host]),  ok.
      
      





最初に、マクロ定義INFO_MSGにejabberd.hrlファイルを含めます。 接続ファイルへのフルパスまたは相対パスを指定する必要があります。具体的には、これはejabberのソースコードにあります。

メッセージはサーバーログ(/var/log/ejabberd/ejabberd.logにあります)に表示され、各〜pの代わりにリストの要素(2番目の引数)があります。



Ejabberdイベント処理



Ejabberdでは、イベント(イベント)およびフック(フック)のメカニズムを使用して、モジュールをモジュールに統合できます。



 ejabberd_hooks:add(Hook, Host, Module, Function, Prioritet) ejabberd_hooks:remove(Hook, Host, Module, Function, Prioritet)
      
      





Ejabberdは、 ホストノードでフックイベントが発生するたびに(すべてのノードをリッスンする場合はglobalを使用して)、 モジュールモジュールのFunction関数を呼び出します(モジュールになるようにMODULEマクロを使用します )。 このリンクで可能なイベントのリストを表示できます。 1つのイベントに複数のサブスクライバーがある場合、それらは順番に実行され、最初に優先度が高くなります。

誰かが何か(メッセージなど)を送信するたびに発生するfilter_packetイベントに興味があります。

モジュールは次のようになります。



 -module(mod_restrictions). -behavior(gen_mod). -include("ejabberd.hrl"). -export([start/2, stop/1, on_filter_packet/1]). start(_Host, _Opts) ->  ejabberd_hooks:add(filter_packet, global, ?MODULE, on_filter_packet, 50),  ok. stop(_Host) ->  ejabberd_hooks:delete(filter_packet, global, ?MODULE, on_filter_packet, 50),  ok. on_filter_packet(Packet) ->  Packet.
      
      





管理パネルへのモジュールの追加



ユーザーとグループを管理するために、モジュールをejabberd Webインターフェースに追加したいと思います。 詳細についてはこちらをご覧ください



必要なファイルを接続し、フックを追加/削除します。



 -include("web/ejabberd_http.hrl"). -include("web/ejabberd_web_admin.hrl"). start(_Host, _Opts) ->  ...  ejabberd_hooks:add(webadmin_menu_main, ?MODULE, web_menu_host, 50),  ejabberd_hooks:add(webadmin_page_main, ?MODULE, web_page_host, 50),  ... stop(_Host) ->  ...  ejabberd_hooks:delete(webadmin_menu_main, ?MODULE, web_menu_host, 50),  ejabberd_hooks:delete(webadmin_page_main, ?MODULE, web_page_host, 50),  ...
      
      







メイン管理メニューにアイテムを追加します。



 web_menu_host(Acc, Lang) ->  Acc ++ [{"mod_restrictions", ?T("Restrictions")}].
      
      





モジュールページ自体:



 web_page_host(_,      #request{method = Method,            q = Query,            path = ["mod_restrictions"],            lang = _Lang}) ->  case Method of    'POST' -> %% Handle database query      case lists:keyfind("act", 1, Query) of        {"act","add_usrgrp"} -> %% add user to group          {"usr",NewUser} = lists:keyfind("usr", 1, Query),          {"grp",NewGroup} = lists:keyfind("grp", 1, Query),          ?INFO_MSG("mod_restrictions: ADD NewUser=~p NewGroup=~p", [NewUser, NewGroup]);        ...        _ -> none      end;    _ -> none  end,  Res = [?XC("h1", "Restriction module manager"),      ?XE("table",[        ?XE("tr",          [?XC("th","Users"),?XC("th","Groups")]        ),        ?XE("tr",          [?XAE("td",[{"style","vertical-align:top;"}],web_user_list()),?XAE("td",[{"style","vertical-align:top;"}],web_group_list())]        )]      )     ],  {stop, Res}; web_page_host(Acc, _) -> Acc.
      
      





ここでは、まずPOST要求を処理してユーザーグループのリストを変更し、次に次のHTMLコードを返します。



 <h1>Restriction module manager</h1> <table><tr><th>Users</th><th>Groups</th></tr><tr><td style="vertical-align:top;">  - <form action="" method="post"><input type="text" name="usr" value=""/><input type="text" name="grp" value=""/><input type="hidden" name="act" value="add_usrgrp"/><input type="submit" name="btn" value="Add"/></form></td><td style="vertical-align:top;">  - <form action="" method="post"><input type="text" name="grp" value=""/><input type="text" name="dest" value=""/><input type="hidden" name="act" value="add_grpdest"/><input type="submit" name="btn" value="Add"/></form></td></tr></table>
      
      





すべてのHTML生成関数は、ファイルejabberd_web_admin.hrlにあります。



データベースを操作する



最も簡単な方法は、ejabberdでMnesiaデータベースを使用することです。



グループにユーザーを含めるためのテーブルと、グループの権限を設定するためのテーブルの2つのテーブルが必要です。

テーブル構造は、アーランレコードを使用して記述されます。



 -record(restrictions_users, {usr, grp}). -record(restrictions_groups, {grp, dest}).
      
      





ユーザーJIDおよびグループフィールドを含むrestriction_usersレコードと、グループおよび方向フィールド(メッセージを送信できる場所)を含むrestriction_groupsレコードを作成しました。



Mnesiaテーブルを操作するには、トランザクションとダーティメソッドの2つの方法があります。 2番目の方法は高速ですが、データベースの整合性を保証するものではありません。 メッセージを処理するときに使用します。



テーブル作成


次に、開始関数で、これらのレコードに対応するテーブルを作成します。 特に再起動しない限り、モジュールの再起動時に上書きされません。



 mnesia:create_table(restrictions_groups, [{disc_copies, [node()]} , {attributes, record_info(fields, restrictions_groups)}, {type, bag}]), mnesia:create_table(restrictions_users, [{disc_copies, [node()]} , {attributes, record_info(fields, restrictions_users)}, {type, bag}]),
      
      





とりわけ、ここでは、テーブルのコピーがハードドライブに保存されることを示します(デフォルトでは、テーブルはRAMにのみ保存されます)。 バッグテーブルのタイプは、フィールドの値が一意でなくても、テーブルの各レコードが一意であることを意味します。



SELECT * FROMテーブル


管理パネルでは、テーブル全体を表示する必要があります。 これを行うには、次の設計を使用できます。



 mnesia:dirty_match_object(mnesia:table_info(,wild_pattern))
      
      





すべてのテーブルエントリのリストが返されます。 さらに、たとえば、 lists:map / 2関数を使用して、HTMLリストからラベルを作成することもできます。



参加する


メッセージを処理する場合、テーブルを結合して、ユーザー(usr)とアクセス許可(dest)の対応を決定する必要があります。 これにはqlcモジュールを使用します。



 Ftemp = fun() ->  Qvve = qlc:q([allow || U <- mnesia:table(restrictions_users),              G <- mnesia:table(restrictions_groups),              (U#restrictions_users.usr == FromUsr++"@"++FromDomain) and              (U#restrictions_users.grp == G#restrictions_groups.grp) and (                (G#restrictions_groups.dest == "all") or                (G#restrictions_groups.dest == ToDomain) or                (G#restrictions_groups.dest == ToUsr++"@"++ToDomain)              )        ]),  qlc:eval(Qvve) end, ?INFO_MSG("mod_restrictions: allow? ~p", [mnesia:transaction(Ftemp)]),
      
      





差出人ユーザーが、ドメインへのユーザーへの書き込み権限または宛先ユーザー自体のすべての許可を持つグループに属している場合、クエリは{atomic、[allow、...]}を返します。



モジュールのパラメーター



ejabberd.cfg設定ファイルからモジュールにパラメーターを渡し、接続文字列をこれに置き換えます。次に例を示します。



 {mod_restrictions, [{deny_message,"    :("}]}
      
      





メッセージがブロックされたら、パラメータで留守番電話のテキストを送信します。

モジュールでは、パラメーター値はget_module_opt関数を使用して取得されます。



 gen_mod:get_module_opt(Host, Module, Opt, Default)
      
      





モジュールからメッセージを送信する



 Attrs = [{"type",Type},{"id","legal"},{"to",To#jid.user++"@"++To#jid.server++"/"++To#jid.resource},{"from",From#jid.user++"@"++From#jid.server++"/"++From#jid.resource}], Els = [{xmlcdata,<<"\n">>},{xmlelement,"body",[],[{xmlcdata,list_to_binary(Message)}]}], DenyMessage = {xmlelement,"message",Attrs,Els}, ejabberd_router:route(From,To,DenyMessage)
      
      





on_filter_packetパラメーターからFrom変数とTo変数を取得し、これらはjidタイプのエントリーを表します。



おわりに



モジュールの全文はここで見ることができます

この記事は基礎として取り上げられています。



All Articles