天天看點

(轉)OpenFire源碼學習之八:MUC使用者聊天室

MUC

(轉)OpenFire源碼學習之八:MUC使用者聊天室

以上屬性存儲在MUCPersistenceManager

private staticConcurrentHashMap<String,MUCServiceProperties> propertyMaps=newConcurrentHashMap<String,MUCServiceProperties>();

用戶端建立房間案例

(轉)OpenFire源碼學習之八:MUC使用者聊天室

第一:用戶端發出查詢請求

[html] view plain copy

<iq id="wcCqI-57" to="[email protected]" type="get">  

  <query xmlns="http://jabber.org/protocol/disco#info"/>  

</iq>  

伺服器将資料包發送到托管在該伺服器元件來處理。

routed = routeToComponent(jid,packet, routed);

伺服器需要在記憶體中判斷房間是否存在,其次呢,傳回外部元件的配置。為确切請求子域的查詢将會作出修改。如果沒有被發現和使用通配符請求,然後再查詢将被提出,在使用通配符這個時候。

然後檢查元件是否被托管在此JVM

擷取MUC元件的資訊

該MUC服務将接收的域MUC的域相比對的所有資料包服務。這意味着,例如,disco 請求應該由服務本身作出回應,而不是依賴在伺服器上處理請求。

根據命名空間找到相應處理——>IQDiscoInfoHandler。

 ​

尋找與所請求的實體相關的DiscoInfoProvider。

我們認為該資料包為機關的接收者的JID的主機。這是DiscoInfoProvider責任提供有關的JID的姓名資訊一起用任何可能的請求節點。

所查詢的房間節點不存在,按照正常的流程伺服器傳回錯誤資訊

<iq type="error" id="wcCqI-57" from="[email protected]" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">  

  <error code="404" type="cancel">  

    <item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>  

  </error>  

用戶端第二輪發送:

<presence id="wcCqI-59" to="[email protected]/test2">  

  <x xmlns="http://jabber.org/protocol/muc"/>  

</presence>  

伺服器處理:

1.将使用者發送的定向存在的實體

  (通知方式發送到該處理程式,當使用者發送了一個指向存在的實體。如果存在的發件人是本地的(這個伺服器)和目标實體不屬于使用者的花名冊,然後發送更新派駐執導的使用者系統資料庫。)

2.廣播到所有連接配接的資源

  (獲得由XMPPAddress聊天的使用者。僅傳回已連接配接到該JVM的使用者。)

伺服器傳回消息:

<message type="groupchat" from="[email protected]">  

  <body>确認配置之前已鎖住該房間,禁止進入。</body>  

</message>  

配置錢鎖定房間,一面别的用建立一樣的,或者申請加入這個房間

<presence id="wcCqI-59" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android"   

          from="[email protected]/test2">  

<x xmlns="http://jabber.org/protocol/muc#user">  

   <item jid="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android"   

          affiliation="owner" role="moderator"/>  

         <status code="201"/>  

</x>  

用戶端發送IQ:

<iq id="wcCqI-60" to="[email protected]" type="get">  

  <query xmlns="http://jabber.org/protocol/muc#owner"/>  

查詢房間擁有者。

伺服器傳回1:

<message type="groupchat" from="[email protected]" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">  

<body>确認配置之前已鎖住該房間,禁止進入。</body>  

伺服器傳回2:

<iq type="error" id="wcCqI-60" from="[email protected]"   

                         to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">  

   <query xmlns="http://jabber.org/protocol/muc#owner"/>  

       <error code="401" type="auth">  

       <not-authorized xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>  

   </error>  

======================================================================

總的對話

用戶端發送C2S - RECV (32671720): 

<iq id="wcCqI-61" to="[email protected]" type="get">  

    <query xmlns="http://jabber.org/protocol/disco#info">  

    </query>  

伺服器傳回

<iq type="error" id="wcCqI-61"   

                             from="[email protected]"   

                             to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">  

     <query xmlns="http://jabber.org/protocol/disco#info"/>  

         <error code="404" type="cancel">  

             <item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>  

         </error>  

以上循環兩次對話,這可能由于debug逾時原因,消息重複發送。

用戶端發送

<presence id="wcCqI-63" to="[email protected]/test2">  

<x xmlns="http://jabber.org/protocol/muc">  

出席消息。

1.當使用者發送一個 directed presence的時候将發送給directedPresenceSent()來處理。如果存在的發件人是本地的(這個伺服器)和目标實體不屬于使用者的花名冊,然後發送更新派駐執導的使用者系統資料庫。

跟蹤所有訓示派駐人員名冊,如果服務被禁用

這裡有兩塊記憶體記錄消息:

private Cache<String,Collection<DirectedPresence>>directedPresencesCache;

跟蹤發送指向派駐到其他實體。

在這個Cache上我們跟蹤每一個 directed presence存在,無論發送者是否托管在這個JVM或其他群集節點。

另一個

private Map<String,Collection<DirectedPresence>>localDirectedPresences;

發送相同directedPresencesCache但隻有不斷派駐指導

使用者連接配接到該JVM。

在方法directedPresenceSent()中主要對兩個變量開始操作,這裡有一個開鎖和解鎖的過程。

updateHandler.directedPresenceSent(packet, jid, recipientJID.toString());

2.路由消息包

被發送到XMPP域的元件路由資料包(這是XMPP域的子域)

首先檢查元件是否被托管在此JVM

存在,交由component.processPacket(packet);出資料包

該MUC服務将接收的域MUC服務的域相比對的所有資料包。

這意味着,例如,disco請求應該由服務本身作出回應,而不是依賴在伺服器上處理請求。

在getChatRoom()方法中會從資料庫中加載了房間的配置(如果房間是持久性的,但被添加到資料庫伺服器啟動或房間可能是舊的房間,這是不存在于記憶體後)

這裡OF伺服器檢查到房間需要重新建立的情況下,它沒有預先建立(或已被删除不知何故,預計委托存在)。

因為房間不存在,是以接下來就該檢測擁有者的建立權限了。依次添加room到記憶體中,以免其他建立者沖突。

開始建立房間事件——>通知其他叢集節點,一個新的空間可用.

檢查用戶端建立密碼或用戶端對MUC的支援

(注:擷取房間元件的基本資訊

Long serviceID = XMPPServer.getInstance().getMultiUserChatManager().

getMultiUserChatServiceID(room.getMUCService().getServiceName());)

<presence id="wcCqI-63" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android"   

                       from="[email protected]/test2">  

    <x xmlns="http://jabber.org/protocol/muc#user">  

         <item jid="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android"   

                                 affiliation="owner" role="moderator"/>  

                <status code="201"/>  

    </x>  

給自己發送出席

<message type="groupchat"    from="[email protected]"   

                     to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">  

用戶端發送:

<iq id="wcCqI-64" to="[email protected]" type="get">  

   <query xmlns="http://jabber.org/protocol/muc#owner">  

   </query>  

</iq >  

根據namespace伺服器将有IQOwnerHandler來處理

refreshConfigurationFormValues()房間配置資訊

伺服器傳回:

<iq type="result" id="wcCqI-64" from="[email protected]"       to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">  

    <query xmlns="http://jabber.org/protocol/muc#owner">  

    <x xmlns="jabber:x:data" type="form">  

    <title>房間配置</title>  

<instructions>  

     已建立房間“room2”。要接受預設配置,請單擊“确定”按鈕。  

     或填寫以下表單以完成設定:  

</instructions>  

<field var="FORM_TYPE" type="hidden">  

   <value>http://jabber.org/protocol/muc#roomconfig</value>  

</field>  

<field var="muc#roomconfig_roomname" type="text-single"   

                        label="房間名稱">  

    <value>room2</value>  

<field var="muc#roomconfig_roomdesc" type="text-single"   

                            label="描述">  

<field var="muc#roomconfig_changesubject" type="boolean"   

                 label="允許占有者更改主題">  

    <value>1</value>  

<field var="muc#roomconfig_maxusers" type="list-single"   

                                       label="最大房間占有者人數">  

    <option label="10">  

        <value>10</value>  

    </option>  

    <option label="20">  

        <value>20</value>  

    <option label="30">  

        <value>30</value>  

    <option label="40">  

        <value>40</value>  

    <option label="50">  

        <value>50</value>  

    <option label="無">  

        <value>0</value>  

     <value>30</value>  

<field var="muc#roomconfig_presencebroadcast" type="list-multi"   

                label="其 Presence 是 Broadcast 的角色">  

    <option label="主持者">  

        <value>moderator</value>  

    <option label="參與者">  

        <value>participant</value>  

    <option label="訪客">  

        <value>visitor</value>  

    <value>moderator</value>  

    <value>participant</value>  

    <value>visitor</value>  

 </field>  

<field var="muc#roomconfig_publicroom" type="boolean"   

              label="列出目錄中的房間">  

<value>1</value>  

<field var="muc#roomconfig_persistentroom" type="boolean"   

label="房間是持久的">  

<value>1</value></field>  

<field var="muc#roomconfig_moderatedroom" type="boolean"   

label="房間是适度的">  

<field var="muc#roomconfig_membersonly" type="boolean"   

label="房間僅對成員開放">  

<field type="fixed">  

<value>注意:預設情況下,隻有管理者才可以在僅用于邀請的房間中發送邀請。</value>  

<field var="muc#roomconfig_allowinvites" type="boolean"   

                       label="允許占有者邀請其他人">  

<field var="muc#roomconfig_passwordprotectedroom" type="boolean"   

                       label="需要密碼才能進入房間">  

<value>0</value>  

<value>如果需要密碼才能進入房間,則您必須在下面指定密碼。</value>  

<field var="muc#roomconfig_roomsecret" type="text-private"   

                       label="密碼"/>  

<field var="muc#roomconfig_whois" type="list-single"   

                       label="能夠發現占有者真實 JID 的角色">  

<option label="主持者">  

     <value>moderators</value>  

</option>  

<option label="任何人">  

     <value>anyone</value>  

<value>anyone</value>  

<field var="muc#roomconfig_enablelogging" type="boolean"   

                       label="登入房間對話">  

     <value>1</value>  

<field var="x-muc#roomconfig_reservednick" type="boolean"   

                       label="僅允許注冊的昵稱登入">  

    </field>  

<field var="x-muc#roomconfig_canchangenick" type="boolean"   

                       label="允許使用者修改昵稱">  

<value>允許使用者注冊房間</value>  

<field var="x-muc#roomconfig_registration" type="boolean"   

                       label="允許使用者注冊房間">  

<value>您可以指定該房間的管理者。請在每行提供一個 JID。</value>  

<field var="muc#roomconfig_roomadmins" type="jid-multi"   

                       label="房間管理者"/>  

<value>您可以指定該房間的其他擁有者。請在每行提供一個 JID。</value>  

<field var="muc#roomconfig_roomowners" type="jid-multi"   

label="房間擁有者">  

<value>test2@8ntmorv1ep4wgcy</value>  

</query>  

用戶端發送1

<iq id="wcCqI-65" to="[email protected]" type="set">  

      <query xmlns="http://jabber.org/protocol/muc#owner">  

      <x xmlns="jabber:x:data" type="submit">  

      <field var="FORM_TYPE" type="hidden">  

          <value>http://jabber.org/protocol/muc#roomconfig</value>  

      </field>  

      <field var="muc#roomconfig_roomname" type="text-single">  

           <value>room2</value>  

      <field var="muc#roomconfig_roomdesc" type="text-single">  

          <value>測試2</value>  

      <field var="muc#roomconfig_roomowners" type="jid-multi">  

          <value>test2@8ntmorv1ep4wgcy</value>  

      </x>  

      </query>  

在這一步操作,是用戶端來設定房間的一些配置資訊,并且儲存到DB(在類LoaclMUCRomm.saveToDB()方法中)

然後儲存使用者(普通使用者,管理者).

服務端傳回1

<message type="groupchat" from="[email protected]" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">  

<body>該房間現在已解鎖。  

</body>  

服務端傳回2

<iq type="result" id="wcCqI-65" from="[email protected]" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android"/>  

<iq id="wcCqI-66" to="[email protected]" type="get">  

<query xmlns="http://jabber.org/protocol/disco#info">  

處理類:IQDiscoInfoHandler

服務端傳回

<iq type="result" id="wcCqI-66" from="[email protected]"       

                   to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">  

<identity category="conference" name="room2" type="text"/>  

<feature var="http://jabber.org/protocol/muc"/>  

<feature var="muc_public"/><feature var="muc_membersonly"/>  

<feature var="muc_moderated"/>  

<feature var="muc_nonanonymous"/>  

<feature var="muc_unsecured"/>  

<feature var="muc_persistent"/>  

<feature var="http://jabber.org/protocol/disco#info"/>  

      <x xmlns="jabber:x:data" type="result">  

           <value>http://jabber.org/protocol/muc#roominfo</value>  

      <field var="muc#roominfo_description" label="描述">  

      <field var="muc#roominfo_subject" label="主題">  

          <value></value>  

      <field var="muc#roominfo_occupants" label="占有者人數">  

          <value>1</value>  

      <field var="x-muc#roominfo_creationdate" label="建立日期">  

         <value>20131202T02:22:08</value>  

     </field>  

用戶端加入房間,首先擷取房間資訊

<iq id="BfI3V-47" to="[email protected]" type="get">  

服務端通過查找伺服器元件擷取房間資訊并傳回如下封包

<iq type="result" id="BfI3V-55" from="[email protected]" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android">  

  <query xmlns="http://jabber.org/protocol/disco#info">  

    <identity category="conference" name="room2" type="text"/>  

    <feature var="http://jabber.org/protocol/muc"/>  

    <feature var="muc_public"/>  

    <feature var="muc_open"/>  

    <feature var="muc_unmoderated"/>  

    <feature var="muc_nonanonymous"/>  

    <feature var="muc_unsecured"/>  

    <feature var="muc_persistent"/>  

    <feature var="http://jabber.org/protocol/disco#info"/>  

    <x xmlns="jabber:x:data" type="result">  

        <value>http://jabber.org/protocol/muc#roominfo</value>  

        <value>測試房間2</value>  

        <value></value>  

        <value>20131202T07:08:32</value>  

  </query>  

用戶端再次發送狀态

<presence id="BfI3V-57" to="[email protected]/test2"><x xmlns="http://jabber.org/protocol/muc"></x></presence>  

服務端傳回:

<presence id="BfI3V-57" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android" from="[email protected]/test2"><x xmlns="http://jabber.org/protocol/muc#user"><item jid="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android" affiliation="owner" role="moderator"/></x></presence>  

<message type="groupchat" from="[email protected]" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android"><body>該房間不是匿名的。</body><x xmlns="http://jabber.org/protocol/muc#user"><status code="100"/></x></message>  

請求使用者發送消息内容

<message id="BfI3V-64" to="[email protected]">  

  <x xmlns="http://jabber.org/protocol/muc#user">  

    <invite to="test1@8ntmorv1ep4wgcy">  

      <reason>請把我加入會議中。</reason>  

    </invite>  

  </x>  

元件将消息發送給用戶端test1,如圖:

(轉)OpenFire源碼學習之八:MUC使用者聊天室

Test1接收邀請

發送消息:

<presence id="6808K-48" to="[email protected]/test1">  

服務端将發送如下消息

<presence id="6808K-48" to="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android" from="[email protected]/test1">  

<item jid="test1@8ntmorv1ep4wgcy/Spark 2.6.3#android" affiliation="none" role="participant"/>  

<presence id="BfI3V-57" to="test1@8ntmorv1ep4wgcy/Spark 2.6.3#android" from="[email protected]/test2">  

<item jid="test2@8ntmorv1ep4wgcy/Spark 2.6.3#android" affiliation="owner" role="moderator"/>  

OK,關于會議室這塊就到次結束。這裡讀起來很難了解很正常。基于xmpp協定的通訊消息太繁瑣了。但是隻要讀者細心debug調試,還是不難的。

我在上面中的jid,如:jid="test2@8ntmorv1ep4wgcy/Spark 2.6.3#Android,這裡面有個#号。而實際上在openfire正常的通訊是沒的

這是本人調試測試多加了個jid屬性。關于jid部分,本人會單獨拿出來寫博文的。歡迎閱讀,不對之處請聯系本人指正。 

繼續閱讀