Эффективный внешний ростеринг с MySQL и ejabberd

вопрос

обратите внимание,что решение этой проблемы находится непосредственно ниже, используя идею Eugen's view!

я пишу модуль чата для управляемого пользователем сайта PHP/MySQL, который позволяет двум пользователям дружить и выбрал eJabberd для системы чата.

я успешно настроил внешнюю аутентификацию с помощью демона PHP, и теперь мне удалось получить дружеские отношения в eJabberd с помощью mod_roster_odbc и заполнения В MySQL rosterusers таблицы вручную. После долгих раскопок мне удалось найти этот конкретный комментарий очень полезно знать, что установить для каждого столбца, чтобы представить эту дружбу в списке друзей для модуля чата.

мой текущий метод обработки дружеских отношений заключается в вставке двух строк в 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');

я не слишком доволен этим, потому что для взаимной дружбы требуется два ряда.

I поймите, что XMPP, по стандарту, позволяет одиночные и двойные связи между пользователями. Как можно было бы заключить по характеру моего вопроса, система друзей моего собственного приложения использует одну строку для представления дружбы.

мои основные вопросы:

  1. можно ли консолидировать эту дружбу в один ряд? Я пробовал некоторые комбинации из этого неофициальная документация, но не имел успеха. Я тестирую, подключаясь к моему серверу XMPP с помощью Клиент Pidgin.
  2. каков наилучший способ синхронизировать две базы данных-друзья и реестр XMPP? Я думаю, что MySQL TRIGGER может быть самым чистым вариантом на данный момент.

если нет, то мой вариант это изменить rosterusers таблица и получить, что ссылаться на строку друга моего собственного приложения, так что он функционирует как внешний ключ базы данных.

Код Решения

я создал представление, как предложил Ойген. Код не самый элегантный, но я протестировал его, и он работает с eJabberd 2.1 на MySQL 5.5.

моя точная настройка использует две базы данных, поэтому я ссылаюсь на базу данных моего основного приложения явно с помощью main_database.table_name.

код представляет собой объединение двух запросов-первый принимает пользователя, друга, а затем второй вставляет друга, пользователя. Я использую 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 только для чтения из POV вашего eJabberd сервер приложений. Это сделало бы его простым, чтобы заменить его на view, что создает необходимые 2 строки из 1 строки в вашей собственной таблице друзей.

не зная структуры вашей собственной таблицы дружбы, я не могу дать вам полный код, но вот что я думал о псевдо-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 в Вид