使用 MySQL 和 ejabberd 进行高效的外部排班

Posted

技术标签:

【中文标题】使用 MySQL 和 ejabberd 进行高效的外部排班【英文标题】:Efficient external rostering with MySQL and ejabberd 【发布时间】:2012-07-06 19:51:19 【问题描述】:

问题

请注意,这个问题的解决方案直接在下面使用 Eugen 的视图思想!

我正在为一个 php/mysql 用户驱动的网站编写一个聊天模块,该网站允许两个用户交朋友,并且选择了 eJabberd 作为聊天系统。

我已经使用 PHP 守护程序成功地设置了外部身份验证,现在我已经成功地通过使用 mod_roster_odbc 并手动填充 MySQL rosterusers 表将友谊导入 eJabberd。经过大量挖掘,我设法找到this particular comment 非常有助于知道将每一列设置为什么,以便在聊天模块的朋友列表中表示这种友谊。

我目前处理友谊的方法是在rosterusers 表中插入两行:

# Relationship user1 => user2
INSERT INTO rosterusers (username, jid, subscription, ask, server, type)
VALUES ('user1', 'user2@myserver.org', 'B', 'N', 'B', 'item');

# Relationship user2 => user1
INSERT INTO rosterusers (username, jid, subscription, ask, server, type)
VALUES ('user2', 'user1@myserver.org', 'B', 'N', 'B', 'item');

我对此不太满意,因为互惠友谊需要两行。

我了解,按照标准,XMPP 允许用户之间的单链路和双链路。正如我的问题的性质所推断的那样,我自己的应用程序的朋友系统使用一行来表示友谊。

我的主要问题:

    是否可以将这种友谊合并到一行中?我已经尝试了这个unofficial documentation 的一些组合,但没有成功。我正在使用 Pidgin 客户端连接到我的 XMPP 服务器进行测试。 保持两个数据库(朋友和 XMPP 名册)同步的最佳方式是什么?我认为 MySQL TRIGGER 可能是目前最干净的选择。

如果不是,那么我的另一个选择是更改 rosterusers 表并让它引用我自己的应用程序的朋友行,以便它像跨数据库外键一样工作。

解决方案代码

我按照 Eugen 的建议创建了一个视图。代码不是最优雅的,但我已经对其进行了测试,它可以在 MySQL 5.5 上与 eJabberd 2.1 一起使用。

我的确切设置使用两个数据库,因此我使用 main_database.table_name 显式引用我的主应用程序的数据库。

代码是两个查询的联合 - 第一个查询 User, Friend,然后第二个插入 Friend, User。我使用UNION ALL 来提高速度,并让“重复”通过。

我认为这是处理问题的一种非常好的方法,因为不需要对应用程序进行任何更改,并且它会立即更新。

CREATE VIEW rosterusers AS

SELECT LCASE(ua1.Username) AS `username`, CONCAT(LCASE(ua2.Username), '@myserver.org') AS `jid`,
'B' AS `subscription`,
'N' AS `ask`,
'N' AS `server`,
'item' AS `type`,
'B' AS `subscribe`,
d1.Created AS `created_at`,
ua2.Username AS `nick`,
'' AS `askmessage`

FROM main_database.User_Friend AS `d1`

INNER JOIN main_database.User AS `ua1` ON `d1`.UserID = `ua1`.ID
INNER JOIN main_database.User AS `ua2` ON `d1`.FriendID = `ua2`.ID

WHERE d1.IsApproved = 1

UNION ALL

SELECT LCASE(ub2.Username) AS `username`, CONCAT(LCASE(ub1.Username), '@myserver.org') AS `jid`,
'B' AS `subscription`,
'N' AS `ask`,
'N' AS `server`,
'item' AS `type`,
'B' AS `subscribe`,
d2.Created AS `created_at`,
ub1.Username AS `nick`,
'' AS `askmessage`

FROM main_database.User_Friend AS `d2`

INNER JOIN main_database.User AS `ub1` ON `d2`.UserID = `ub1`.ID
INNER JOIN main_database.User AS `ub2` ON `d2`.FriendID = `ub2`.ID

WHERE d2.IsApproved = 1;

【问题讨论】:

【参考方案1】:

IIUC,rosterusers 表在您的eJabberd 服务器应用程序的 POV 中是只读的。这会很简单,用view 替换它,这会在您自己的朋友表中从 1 行中创建所需的 2 行。

不知道自己友谊表的结构,我不能给你完整的代码,但是这里是我认为的伪SQL

CREATE VIEW rosterusers AS SELECT * FROM (
    SELECT 
        selfuser.name AS username, 
        frienduser.jid AS jid,
        -- ....,
        selfuser.jid AS jid_as_id
    FROM
        users AS selfuser
        INNER JOIN friendships ON ....
        INNER JOIN users AS frienduser ON ...
    UNION SELECT 
        frienduser.name AS username, 
        selfuser.jid AS jid,
        -- ....,
        frienduser.jid AS jid_as_id
    FROM
        users AS selfuser
        INNER JOIN friendships ON ....
        INNER JOIN users AS frienduser ON ...
);

然后

SELECT
    username, jid, subscription, ask, server, type
FROM rosterusers
WHERE jid_as_id='user1@myserver.org'

应该给你 2 行,一个来自视图中 UNION 的每个部分

【讨论】:

是的,出于所有意图和目的,rosterusers 是只读的。创建视图是个好主意!

以上是关于使用 MySQL 和 ejabberd 进行高效的外部排班的主要内容,如果未能解决你的问题,请参考以下文章

使用自定义 mysql 模式的模块扩展 ejabberd?

如果我使用 Ejabberd 身份验证和 JWT,我不需要注册用户吗?

使用 asmack 访问连接到 Ejabberd 的 MySQL

来自 mysql 存档的 ejabberd 同步消息

ejabberd 节点的集群如何工作?

用 Mysql 配置 ejabberd,找不到错误 p1_mysql.app