Tigase8.0 源代碼分析:二、MUC源碼分析


XMPP在其XEP-0045擴展中定義了一個用於多用戶文本會議(群聊)的協議,類似於聊天室、QQ群等。由於它作為一個標准協議在定義模型上力求完備,涵蓋了現實中的絕大部分IM產品模型,而現實中的IM產品基本都只實現了XMPP定義的模型中的一個子集。


XMPP定義的一些基本概念:

房間:房間的JID標識 <room@service> (例如, <jdev@conference.jabber.org>), 這里 "room" 是房間的名稱而 "service" 是多用戶聊天服務運行所在的主機名

房客:房客的JID標識<room@service/nick>,nick是房客在房間的昵稱

崗位:表達了用戶和房間的長期關系。XMPP定義的崗位有:所有者(owner)、管理者(admin)、成員(member)、排斥者(outcast)

角色:表達了用戶和房間的臨時聯系,它只存在與一次訪問期間。XMPP定義的角色有:主持人(moderator)、與會者(paticipant)、游客(visitor)

有關崗位、角色及其權限詳細描述,參考協議規范描述(角色、崗位和權限)

 

pom.xml里加入 依賴引用

      <dependency>
            <groupId>tigase</groupId>
            <artifactId>tigase-muc</artifactId>
            <version>3.0.0-SNAPSHOT</version>
        </dependency>

 

config.tdsl 配置文件中加入配置:

muc(class: tigase.muc.MUCComponent) {
  defaultRoomConfig {
       'tigase#presence_delivery_logic' = 'PREFERE_LAST'
       'muc#roomconfig_persistentroom' = 'true'
    }
}

  

 MUC源碼首先從 MUCComponent 這個組件開始分析 :

@Bean(name = "muc", parent = Kernel.class, active = true)
@ConfigType(ConfigTypeEnum.DefaultMode)
@ClusterModeRequired(active = false)
public class MUCComponent
		extends AbstractKernelBasedComponent {}在

 在前一節已說明怎么掃描加載相關的Class,類似這里,加載Kernel.class的時候,會把parent=Kernel.class的Bean全部加載到容器中

MUCComponent 也實現了RegistrarBean,在初始化的時候,會被調用 public void register(Kernel kernel) {} 函數進行注冊工作

public abstract class AbstractKernelBasedComponent
		extends AbstractMessageReceiver
		implements XMPPService, DisableDisco, RegistrarBean {}

  

由於用戶客戶端發來的MUC消息協議為:to=<room@service/nick> 例如 llooper@muc.llooper/spark ,目的地上直接表示到muc.組件上,所以MUC模塊入口就是在MUCComponent 類processPacket(Packet packet) 方法上

	@Override
	public void processPacket(Packet packet) {
		stanzaProcessor.processPacket(packet);
	}

  

 

public void processPacket(Packet packet) {
		if (log.isLoggable(Level.FINER)) {
			log.finer("Received: " + packet.getElement());
		}
	               //查找是否為Response模式,則由Handler來處理
			Runnable responseHandler = responseManager.getResponseHandler(packet);

			boolean handled;
			if (responseHandler != null) {
				handled = true;
				responseHandler.run();
			} else {
			//否則調用處理包的函數
				handled = this.process(packet);
			}

			if (!handled) {
				final String t = packet.getElement().getAttributeStaticStr(Packet.TYPE_ATT);
				final StanzaType type = (t == null) ? null : StanzaType.valueof(t);

				if (type != StanzaType.error) {
					throw new ComponentException(Authorization.FEATURE_NOT_IMPLEMENTED);
				} else {
					if (log.isLoggable(Level.FINER)) {
						log.finer(packet.getElemName() + " stanza with type='error' ignored");
					}
				}
			}
。。。。。。
}

  

 

	private boolean process(final Packet packet) throws ComponentException, TigaseStringprepException {
		boolean handled = false;
		if (log.isLoggable(Level.FINER)) {
			log.finest("Processing packet: " + packet.toString());
		}
                //找到匹配的Module來處理
		for (Module module : this.modules) {
			if (module.canHandle(packet)) {
				handled = true;
				if (log.isLoggable(Level.FINER)) {
					log.finer("Handled by module " + module.getClass());
				}
				module.process(packet);
				if (log.isLoggable(Level.FINEST)) {
					log.finest("Finished " + module.getClass());
				}
			}
		}
		return handled;
	}

 例如MUC中實現的Module有如下:

 

這里的邏輯比較簡單,也就是根據包的節類型等信息,來匹配感興趣的處理Module,來進行處理

 再來看下 module.canHandle(packet) 是怎么樣找到匹配的Module來處理的:

	default boolean canHandle(Packet packet) {
		Criteria criteria = getModuleCriteria();
		return criteria != null && criteria.match(packet.getElement());
	}

  

private final String[] names;
private final String[] xmlns;

@Override public boolean ElemPathCriteria.match(Element element) {           //判斷<iq> packet的名字如iq是否和本module中定義name一致 boolean match = element.getName().equals(names[0]); if (match && xmlns[0] != null) {
               //並且判斷命名空間是否一致 match &= xmlns[0].equals(element.getXMLNS()); } Element child = element; int i = 1;
          //例如packet <iq><set>xxx</set></iq> 則name為數組{"iq","set"},前面判斷了iq,這里判斷set是否一致,如果還存在子節點,則依次比較是否一致 for (; i < names.length; i++) { String n = names[i]; String x = xmlns[i];                // child = child.getChildStaticStr(n, x); match &= child != null; if (!match) { return match; } } // TODO Auto-generated method stub return match; }

  

例如針對出muc的 <presence> 由 PresenceModuleImpl 進行業務邏輯處理

@Bean(name = PresenceModuleImpl.ID, parent = MUCComponent.class, active = true)
public class PresenceModuleImpl
        extends AbstractMucModule
        implements PresenceModule {

    protected static final Logger log = Logger.getLogger(PresenceModule.class.getName());
    private static final Criteria CRIT = ElementCriteria.name("presence");

}

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM