1 协议层:
XMPP扩展协议已经定义了消息回执,参见 http://xmpp.org/extensions/xep-0184.html
同样也定义了聊天状态,参见 http://xmpp.org/extensions/xep-0085.html
XEP-0184: Message Delivery Receipts
Example 3. A content message with receipt requested
- <message
- from='northumberland@shakespeare.lit/westminster'
- id='richard2-4.1.247'
- to='kingrichard@royalty.england.lit/throne'>
- <body>My lord, dispatch; read o'er these articles.</body>
- <request xmlns='urn:xmpp:receipts'/>
- </message>
Note: A sender MUST include an 'id' attribute on every content message that requests a receipt, so that the sender can properly track ack messages.
The recipient shall generate an ack message if and only if (1) it supports the Message Delivery Receipts protocol and (2) it is configured to return receipts, either globally or for this recipient (otherwise it MUST NOT return a receipt and SHOULD NOT return an error).
Example 4. A message delivery receipt
- <message
- from='kingrichard@royalty.england.lit/throne'
- id='bi29sg183b4v'
- to='northumberland@shakespeare.lit/westminster'>
- <received xmlns='urn:xmpp:receipts' id='richard2-4.1.247'/>
- </message>
When the recipient sends an ack message, it SHOULD ensure that the message stanza contains only one child element, namely the <received/> element qualified by the 'urn:xmpp:receipts' namespace. In addition, it SHOULD include an 'id' attribute that echoes the 'id' attribute of the content message. Naturally, intermediate entities might add other extension elements to the message when routing or delivering the receipt message, e.g., a <delay/> element as specified in Delayed Delivery [11].
XEP-0085: Chat State Notifications
Example 3. User Sends Initial Content Message With <active/> Notification
<message
from='bernardo@shakespeare.lit/pda'
to='francisco@shakespeare.lit'
type='chat'>
<body>Who's there?</body>
<active xmlns='http://jabber.org/protocol/chatstates'/>
</message>
Example 4. Contact's Client Sends Content Message Reply With <active/> Notification
<message
from='francisco@shakespeare.lit/elsinore'
to='bernardo@shakespeare.lit/pda'
type='chat'>
<body>Nay, answer me: stand, and unfold yourself.</body>
<active xmlns='http://jabber.org/protocol/chatstates'/>
</message>
Because the User now knows that the Contact supports chat state notifications, the User can send other notification types.
Example 5. User Sends Standalone <composing/> Notification
<message
from='bernardo@shakespeare.lit/pda'
to='francisco@shakespeare.lit/elsinore'
type='chat'>
<composing xmlns='http://jabber.org/protocol/chatstates'/>
</message>
Example 6. User Sends a Content Message Reply With <active/> Notification
<message
from='bernardo@shakespeare.lit/pda'
to='francisco@shakespeare.lit/elsinore'
type='chat'>
<body>Long live the king!</body>
<active xmlns='http://jabber.org/protocol/chatstates'/>
</message>
And so forth.
State Definition Suggested Triggers
<active/> | User is actively participating in the chat session. | User accepts an initial content message, sends a content message, gives focus to the chat session interface (perhaps after being inactive), or is otherwise paying attention to the conversation. |
<inactive/> | User has not been actively participating in the chat session. | User has not interacted with the chat session interface for an intermediate period of time (e.g., 2 minutes). |
<gone/> | User has effectively ended their participation in the chat session. | User has not interacted with the chat session interface, system, or device for a relatively long period of time (e.g., 10 minutes). |
<composing/> | User is composing a message. | User is actively interacting with a message input interface specific to this chat session (e.g., by typing in the input area of a chat window). |
<paused/> | User had been composing but now has stopped. | User was composing but has not interacted with the message input interface for a short period of time (e.g., 30 seconds). |
The following figure attempts to capture the most common state transitions in visual form (all four of the states shown can also transition to the GONE state).
o (start) | | INACTIVE <--> ACTIVE <--> COMPOSING <--> PAUSED | | | | +---<---<---<---<---<---<---<---<---<---+
Note: Other transitions are not forbidden if the developers of an implementation feel that such transitions are desirable (e.g., INACTIVE to PAUSED if a user returns to a chat session interface containing an unfinished message).
2 实现层
openfire项目中,今年(2011)3月已经有人提交了XEP0184的feature,参见 http://issues.igniterealtime.org/browse/OF-434
Add support for XEP-0184: Message Delivery Receipts
不过正如 wroot 对我的回复所述,此特性的release还遥遥无期:
至于XEP-0085 ,目前主流的实现都是支持的 ,而且这个逻辑更多是在客户端,比较简单。
3 解决方案
- 如果可能,自己修改openfire,实现此特性即可;或者使用插件的方式去实现。 其实难度不大,只是openfire是开源项目,多人异地协作,目前相对稳定,稳步发展;所以增加这种特性比自己实现还缓慢,需要有人推进才行。
- 曲线救国: 对于message消息,自己可以做一些私有的约定,比如服务器做一些响应,客户端额外发一些IQ等。当然不太推荐这种方式。
以上是两种思路,具体实现还要看产品或项目的具体需求,比如是否严格控制网络带宽,是否严格要求信息投递成功率等。
消息回执和聊天状态都是用户体验相关的feature,所以需要在功能稳定和流量等因素许可的前提下去优化和改进。
同理,类似 geo-location 或 LBS 相关的feature,我们也可以自己去实现。
比如 openfireLBS 插件 https://github.com/node/openfireLBS