movim/moxl

此包已被放弃,不再维护。没有建议的替代包。

Moxl 是专为 Movim 项目定制的轻量级 PHP XMPP 库

dev-master 2018-05-18 20:58 UTC

This package is not auto-updated.

Last update: 2020-01-24 15:12:02 UTC


README

Moxl 是 Movim 项目的官方 XMPP 库。它从版本 0.6(包含)开始替代 Jaxl。

历史

Moxl(为 Movim XMPP 库)于 2012 年夏天由 Timothée Jaussoin 开发,当时开发团队决定替换 Jaxl 库,因为 Jaxl 库开始无法满足 Movim 项目的需求。

Moxl 在 2014 年秋天部分重写,以与新的 Movim WebSocket 守护程序一起工作。从那时起,库仅与 BOSH 一起工作。所有与 BOSH 相关的源代码都已移除。

功能

其工作方式与 Jaxl 基本不同。Moxl 是为了仅通过 HTTP(S) 与 XMPP 服务器通信而创建的。这就是为什么没有同步模式或系统可以使其像守护程序一样工作。

Moxl 管理由 Movim 守护程序接收到的 XMPP 数据包,解析它们,并通过同一守护程序将生成的事件发送到 Movim 核心。

基本上,Moxl 总是作为一个异步库工作。

会话

为了在 Moxl 请求之间保持会话打开,每个请求都将所有会话变量存储在内存中。因此,其集成基于 Session 类。

命名空间

与许多 XMPP 库不同,Moxl 更倾向于通过 XMPP 命名空间而不是通过扩展(XEP)处理消息。

关于功能的详细信息

认证

Moxl 认证序列基于 SASL2 库。您可以在以下位置找到它:GitHub PHP SASL2 认证库

XMPP 资源

认证系统也进行了适配,以便您可以轻松连接到强制执行资源的服务器(如 Gmail 或 Facebook)。XMPP 资源是放置在 JID(Jabber ID 或更常见的 XMPP 网络上用户的地址)末尾的字符串,允许您指定用于发送消息的客户端。用户可以同时连接到多个客户端。例如,如果您在

Moxl 的默认资源为 moxl 后跟一个随机哈希(这使得地址看起来像 [email protected]/moxl23ER4S),但一些服务器强制执行特定的资源。例如,Gmail XMPP 服务器使用一个哈希,使得地址看起来像

Moxl 可以适应 XMPP 服务器的指令,并允许您无缝连接到广泛的服务器。

XMPP 支持

数量 名称 实现 注释
XEP-0004 数据表单 用于账户创建表单 + 所有 Pubsub 配置
XEP-0012 最后活动
XEP-0030 服务发现
XEP-0045 多用户聊天
XEP-0048 书签 MUC + URL + PubsubSuscription 支持
XEP-0049 私有 XML 存储 用于存储 Movim 账户配置
XEP-0050 即时命令
XEP-0054 vcard-temp 添加性别 + 婚姻元素(非标准)
XEP-0059 结果集管理 用于查询 Pubsub 和 PEP 项
XEP-0060 发布-订阅 为群组和微博实现
XEP-0070 通过 XMPP 验证 HTTP 请求 仅消息部分
XEP-0071 XHTML-IM 用于 Pubsub 发布
XEP-0077 带内注册 jabber: x:oob 支持
XEP-0080 用户位置 尚未 用于 XEP-0277 消息接收 + 联系位置
XEP-0084 用户头像 读写
XEP-0085 聊天状态通知 仅 composing/paused
XEP-0092 软件版本 部分 仅发送
XEP-0100 网关交互
XEP-0107 用户心情 只读
XEP-0108 用户活动 只读
XEP-0115 实体能力
XEP-0118 用户设置 只读
XEP-0124 通过同步 HTTP 的双向流 (BOSH) 不再
XEP-0153 XEP-0153: 基于 vCard 的头像
XEP-0157 XMPP 服务的联系地址 在 Movim 中处理
XEP-0163 个人事件协议 参见 XEP-0277
XEP-0172 用户昵称 联系人昵称
XEP-0184 消息投递回执
XEP-0199 XMPP Ping
XEP-0206 XMPP Over BOSH 不再
XEP-0224 注意
XEP-0231 二进制位 用于贴纸功能
XEP-0245 /me 命令
XEP-0256 存在中的最后活动
XEP-0277 通过 XMPP 的微博
XEP-0280 消息炭
XEP-0292 vCard4 Over XMPP
XEP-0313 消息存档管理 最高到 urn:xmpp:mam:2
XEP-0330 Pubsub 订阅 使用 PEP,由 Movim 团队提出
XEP-0333 聊天标记
XEP-0334 消息处理提示
XEP-0363 HTTP 文件上传
XEP-0385 无状态内联媒体共享 (SIMS) 部分,与 XEP-0363 协同工作

内部操作

库结构

以下是组成 Moxl 的目录结构

Moxl/
|-- Stanza/
|
`-- Xec
    |-- Action/
    `-- Payload/

Stanza

此目录包含一组用于通过构建 XML 数据包生成有效 Stanza(XMPP 请求)的函数。这些函数按主题分组在多个文件中(Presence.phpMessage.php...)。

因此,这些函数返回一个包含 XML 的字符串,该字符串将被发送到请求者。

XEC

XEC(XMPP 事件控制器)是 Moxl 的一个子模块。它智能地管理通过 Moxl 传递的请求。XEC 分为两部分;操作和有效载荷。

在两种情况下,都需要开发者开发 XECPayload 和 XECHandler,以便将 Moxl 的事件与目标应用程序的事件链接起来。

操作

XEC 操作是对 XMPP 服务器的请求。在这种情况下,XEC 提供了一种系统,让 Moxl "记住"过去的请求,并将结果发送回适当的请求者。

namespace Moxl\Xec\Action\Roster;

use Moxl\Xec\Action;
use Moxl\Stanza\Roster

class AddItem extends Action
{
    private $_to;

    public function request()
    {
        $this->store();
        Roster::add($this->_to);
    }

    public function setTo($to)
    {
        $this->_to = $to;
        return $this;
    }

    public function handle($stanza)
    {
        var_dump('Handle item');
    }

    public function errorServiceUnavailable()
    {
        var_dump('Handle the Error !');
    }
}

本示例展示了“将联系人添加到联系人列表”的动作,此动作继承自 XECAction。现在,您可以使用以下方式添加联系人:

use Moxl\Xec\Action\Roster\AddItem;

$c = new AddItem;
$c->setTo('[email protected]')
  ->request();

请注意,以下行是强制性的,以确保 XEC 初始化请求并稍后管理其结果:

$this->store();

是强制性的,以确保 XEC 初始化请求并在稍后管理其结果。

请求系统

store() 动作将实例保存为其当前状态,并将其存储在包含所有当前需求的数组中。此实例将由 XMPP 请求 ID 标识。

为了将结果与请求匹配,XECHandler 将检查句子的 ID 是否存在于数组中,并重新实例化该类。因此,开发人员甚至不会知道请求和结果是在两次不同的执行(通过 XMPP 服务器上的两个不同请求)中进行的。请求由 request() 方法启动,其结果由同一实例的 handle() 方法接收。

响应

如果一切顺利,请求的结果将通过 handle($stanza) 方法接收,其中 $stanza 是转换为 SimpleXML 格式的结果。

类的属性值也会保存,并在结果到达时返回。如果您想在请求和结果之间保留一些值,则可以自由地使用该功能。

错误处理

请求可以正确处理,也可以在 XMPP 端引发错误。XEC 可以处理此错误结果,并尝试调用请求类中的适当方法。更具体地说,它会寻找一个类似于 CamelCase 格式给出的错误字符串名称的方法。

您可以自由地处理这些错误或忽略它们。无论如何,它们将通过 syslog 在 /var/log/user.log 中记录。在下面的示例中,您可以查看应处理 errorServiceUnavailable 错误的方法。此错误处理系统很有趣,因为它可以直接从浏览器(就像 Movim 所做的那样)警告用户。

有效载荷

有效载荷类似于动作的对立面。它们是由服务器发送但不是由客户端(在我们的情况下是 Moxl)请求的 stanza。通常,它是由联系人发送的消息。同样,Moxl 尝试通过 XEC 理解它是什么类型的 stanza。

这里的操作略有不同。以下是从 XECHandler 中提取的用于处理有效载荷 stanza 的哈希提取的一部分。

require('XECHandler.array.php');

$name = $s->getName();
$ns = $s->getNamespaces();
$node = (string)$s->attributes()->node;

if(is_array($ns))
    $ns = current($ns);

$hash = md5($name.$ns.$node);

MoxlLogger::log('XECHandler : Searching a payload for "'.$name . ':' . $ns . ' [' . $node . ']", "'.$hash.'"');

基本上,XECHandler 为“类型”的有效载荷生成一个唯一的哈希。要生成它,它使用三个元素:

  • 名称:stanza 的名称
  • ns:stanza 的命名空间
  • 节点:如果存在,则为“节点”属性的名称(大多数情况下它是空的,但对于来自特定 pubsub 节点的有效载荷来说是必须的)。

示例

当您的联系人之一在他的微博动态中发布帖子时,XMPP 服务器就是这样通知 Movim 的:

<event xmlns='http://jabber.org/protocol/pubsub#event'>
  <items node='urn:xmpp:microblog:0'>
    <item id='1cb57d9c-1c46-11dd-838c-001143d5d5db' publisher='[email protected]'>
     <entry xmlns='http://www.w3.org/2005/Atom'>
       <title type='text'>hanging out at the Caf&amp;#233; Napolitano</title>
       <link rel='alternate'
             type='text/html'
             href='http://montague.lit/romeo/posts/1cb57d9c-1c46-11dd-838c-001143d5d5db'/>
       <link rel='alternate'
             href='xmpp:[email protected]?;node=urn%3Axmpp%3Amicroblog%3A0;item=1cb57d9c-1c46-11dd-838c-001143d5d5db'/>
       <id>tag:montague.lit,2008-05-08:posts-1cb57d9c-1c46-11dd-838c-001143d5d5db</id>
       <published>2008-05-08T18:30:02Z</published>
       <updated>2008-05-08T18:30:02Z</updated>
     </entry>
   </item>
</event>
</items>

从片段中您可以看到

  • 名称:item
  • ns:http://jabber.org/protocol/pubsub#event
  • 节点:urn:xmpp:microblog:0

然后 XECHandler 将对 $name.$ns.$node 进行 MD5 哈希处理,并在 XECHandler.array.php 中包含的数组中搜索生成的字符串。

这里的字符串结果是 96c06e02022480352b6c581286b7eefb

$hashToClass = array(
    '9b98cd868d07fb7f6d6cb39dad31f10e' => 'Message',
    'e83b2aea042b74b1bec00b7d1bba2405' => 'Presence',

    '96c06e02022480352b6c581286b7eefb' => 'Post'
    );

如果生成的字符串是数组中的键之一,则将与类对应的值实例化,并调用 handle() 方法。

namespace Moxl\Xec\Payload;

class Post extends Payload
{
    public function handle($stanza) {
        var_dump('Post received');
    }
}

在上面的示例中,所有类型的 Microblog 帖子都将由该类处理。然后您可以对该收到的 $stanza 做任何您想做的事情。

深入研究

适当处理器的搜索不仅限于一个层级,就像您在上面的示例中看到的那样。XECHandler 还会在 stanza 中搜索它们,以尝试找到对开发者有意义的子信息,并在它们上派发事件。

深入研究最多限于三个层级(对应三个 XML 层级),主要是出于性能考虑。

数据包,与 Movim 的通信

为了标准化和统一发送到 Movim 的事件,有效载荷和动作可以发出由 Moxl 生成的唯一键标识的数据包。

这些数据包可以从 handle() 方法或错误方法中发出。

示例

以下示例将帮助我们精确理解数据包系统的工作方式。

namespace Moxl\Xec\Payload;

class SASLFailure extends Payload
{
    public function handle($stanza, $parent = false)
    {
        $sd = new \Modl\SessionxDAO;
        $sd->delete(SESSION_ID);

        $this->pack($stanza->children()->getName());
        $this->deliver();
    }
}

此有效载荷管理失败的 SASL 身份验证的情况。在销毁会话后,将调用两个相对方法的两个数据包。

  • $this->pack() 创建包含我们计划发送到 Movim 核心的数据的包(您可以放入任何类型的数据)。
  • $this->deliver() 将数据包发送到 Movim 事件管理器。

密钥生成

密钥将由数据包自动生成。每个数据包,通过一个键标识,将向 Movim 核心触发一个独特的事件。每个感兴趣的 Movim 小部件可以使用此页面上描述的方法请求接收此特定事件 [[en:dev:widgets#registerevent_event_key_method|执行环境]] FIXME。

每个密钥使用两种特定的模式生成。

对于动作

[last namespace]_[classname]_[method] 使用小写。

在成功执行 Moxl\Xec\Action\Vcard\Get 动作的情况下,我们将得到: vcard_get_handle。如果动作后跟 XMPP 错误,Moxl 将应用相同的模式: vcard_get_erroritemnotfound

对于有效载荷

[classname] 使用小写。

在我们的示例中,密钥将是: saslfailure