Сварка
Важно
Jami source code tends to use the terms (un)ban, while the user interface uses the terms (un)block.
Синоспис
Целью этого документа является описание того, как будут реализованы групповые чаты (также известные как ** swarm chat**) в Jami.
swarm - это группа, способная обсуждать без каких-либо центральных властей устойчивым образом. Действительно, если два человека не имеют никакой связи с остальной частью группы (т.е. выключение Интернета), но они могут связаться друг с другом (например, в LAN или в подсети), они смогут отправлять сообщения друг другу, а затем, когда это возможно, смогут синхронизировать с остальной частью группы.
Итак, «сварм» определяется следующим образом:
Способность делиться и сливаться по мере соединения.
Все должны быть в состоянии передать сообщение всей группе.
Нет центрального органа, не может полагаться на какой-либо сервер.
Устройства должны быть в состоянии проверить действительность старых сообщений и воспроизвести всю историю.
ПФС на транспорте.
Главная идея заключается в том, чтобы получить синхронизированное дерево Меркл с участниками.
Мы определили четыре способа чат-сварма, которые мы хотим реализовать:
Один-на-один, в основном, это тот случай, который мы имеем сегодня, когда вы обсуждаете с другом
ADMIN_INVITES_ONLY обычно класс, где учитель может приглашать людей, но не студентов
ЗАВИТЕТ_СОЛЬНО частную группу друзей
ПУБЛИК в основном открытый форум
Сценарии
Создать скопление
Боб хочет создать новый рог
Bob creates a local Git repository.
Затем он создает первоначальный подписанный договор с следующим:
Его публичный ключ в
/admins
Его сертификат устройства в ̀ /устройства
Его КРЛ в ̀ /crls`
Хеш-адрес первого коммита становится идентификатором разговора.
Боб объявляет своим другим устройствам, что он создает новый разговор. Это происходит через приглашение присоединиться к росту, отправленному через DHT к другим устройствам, связанным с этой учетной записью.
Добавление кого-то
Алиса добавляет Боба
Алиса добавляет Боба в репо:
Добавляет приглашенный URI в
/invited
Добавляет КРС к
/crls
Алиса отправляет запрос на DHT
Принимая приглашение
Алиса получает приглашение присоединиться к раму создания
Она принимает приглашение (если откажется, ничего не сделает, она просто останется в приглашенном и Алиса никогда не получит никакого сообщения)
Связь между Алисой и Бобом завершена.
Alice pull the Git repo of Bob. WARNING this means that messages need a connection, not from the DHT like today.
Алиса подтверждает обязательства Боба
Чтобы подтвердить, что Алиса является членом, она удаляет приглашение из каталога
/invited
, а затем добавляет свой сертификат в каталог/members
Как только все обязательства подтверждены и на ее устройстве, другие члены группы обнаружены Алис. вместе с этими сверстниками, она будет строить DRT (объясняется ниже) с Бобом как бутстрап.
Посылаю сообщение
Алиса отправляет сообщение
Посылать сообщение довольно просто. Алиса пишет сообщение в следующем формате:
{
"type": "text/plain",
"body": "coucou"
}
and adds her device and CRL to the repository if missing (others must be able to verify the commit). Merge conflicts are avoided because we are mostly based on commit messages, not files (unless CRLS + certificates but they are located). Then she announces the new commit via the DRT with a service message (explained later) and pings the DHT for mobile devices (they must receive a push notification).
Для пинга других устройств, отправитель отправляет другим членам SIP-сообщение с миметипом = «приложение/им-gitmessage-id» содержит JSON с «deviceId», который отправляет сообщение, «id» сопутствующего разговора, и «заверять»
Получение сообщения
Боб получает сообщение от Алисы
Bob do a Git pull on Alice
Завершения должны быть проверены через крючок
Если все коммиты валидны, они хранятся и отображаются.
If all commits are not valid, pull is canceled. Alice must reestablish her state to a correct state.
Подтверждение обязательства
Чтобы избежать того, чтобы пользователи наталкивали некоторые нежелательные коммиты (с конфликтами, ложными сообщениями и т. Д.), каждый коммит (от старейшего до самого нового) должен быть проверен перед слиянием удаленной ветви:
Примечание
If the validation fails, the fetch is ignored and we do not merge the branch (and remove the data), and the user should be notified.
If a fetch is too big, it’s not merged.
Для каждого обязательства проверьте, что устройство, которое пытается отправить обязательство, в данный момент разрешено и что сертификаты присутствуют (в устройствах для устройства и в членах или администраторах для эмитента).
У комитета есть 2 родителя, так что это слияние, ничего больше не подтверждается здесь
У обязательства 0 родителей, это первоначальное обязательство:
Проверьте, что добавлен сертификат администратора
Проверьте, что сертификат устройства добавлен
Добавлены КРС
Проверьте, что нет дополнительного файла
Комбинат имеет 1 родитель, сообщение комбита является JSON с типом:
Если текст (или другой тип мима, который не меняет файлы)
Проверка подписи из сертификата в репо
Проверьте, что не добавлено никаких странных файлов вне сертификата устройства или удалено
Если голосовать
Проверьте, поддерживается ли voteType (запрет, отторжение)
Проверьте, что голосование - для пользователя, который подписывает обязательство
Check that vote is from an admin and device present and not banned
Проверьте, что не добавлено и не удалено никаких странных файлов
Если член
Если добавляется
Проверьте, что обязательство правильно подписано.
Проверьте, что сертификат добавлен в / приглашен
Проверьте, что не добавлено и не удалено никаких странных файлов
Если ONE_TO_ONE, проверьте, что у нас только один администратор, один член
Если ADMIN_INVITES_ONLY, проверьте, что приглашение от администратора
Если присоединится
Проверьте, что обязательство правильно подписано.
Проверьте, что устройство добавлено
Проверьте, что приглашение переведено членам
Проверьте, что не добавлено и не удалено никаких странных файлов
Если запрещено
Проверьте, что голосование действительно.
Проверьте, что пользователь запрещен через администратора
Проверьте, что сертификат на член или устройство переведен на запрещенный.
Проверьте, удалены ли только файлы, связанные с голосованием
Проверьте, что не добавлено и не удалено никаких странных файлов
уведомлять пользователя, что они могут быть с старой версией или что коллега пытался отправить нежелательные коммитации
Запретить устройство
*Алиса, Боб, Карла, Денис в роге.
Это один из самых сложных сценариев в нашем контексте.
Временные штампы созданных обязательств
Если присутствуют несколько устройств администратора и если Алиса может говорить с Бобом, но не с Денисом и Карлой; Карла может говорить с Денисом; Денис запрещает Алису, Алиса запрещает Денису, каково будет состояние, когда 4 члена объединят разговоры.
Устройство может быть взломан, украдено или его сертификат может истечь.
Подобные системы (с распределенными групповыми системами) не так много, но это несколько примеров:
[mpOTR не определяет, как запретить кого-то]
Сигнал, без центрального сервера для группового чата (EDIT: они недавно изменили этот пункт), не дает возможности запретить кого-то из группы.
Эта система голосования нуждается в человеческом действии, чтобы запретить кого-то или должна основываться на информации о ОКР из хранилища (потому что мы не можем доверять внешним ОКР)
Удалить устройство из разговора
Это единственная часть, в которой должен быть консенсус, чтобы избежать разделения разговора, например, если два члена выкинут друг друга из разговора, что будет видеть третий?
Это необходимо для обнаружения отмененных устройств или просто избегания присутствия нежелательных людей в общественной комнате.
Алиса снимает Боба
Важно
Alice MUST be an admin to vote.
Во-первых, она голосует за запрет Боба. Для этого она создает файл в /votes/ban/members/uri_bob/uri_alice (члены могут быть заменены устройствами для устройства, или приглашены для приглашений или администраторов для администраторов) и обязуется
Затем она проверяет, разрешено ли голосование. Это означает, что >50% администраторов согласны запретить Боб (если она одна, это наверняка больше 50%).
Если голосование будет решено, файлы в /votes/ban могут быть удалены, все файлы для Боба в /members, /admins, /invited, /CRLs, /devices могут быть удалены (или только в /devices, если это устройство, которое запрещено) и сертификат Боба может быть помещен в /banned/members/bob_uri.crt (или /banned/devices/uri.crt, если устройство запрещено) и обязаны репо
Затем Алиса информирует других пользователей (за исключением Боба)
Alice (admin) re-adds Bob (banned member)
If she votes for unbanning Bob. To do that, she creates the file in /votes/unban/members/uri_bob/uri_alice (members can be replaced by devices for a device, or invited for invites or admins for admins) and commits
Затем она проверяет, разрешено ли голосование. Это означает, что >50% администраторов согласны запретить Боб (если она одна, это наверняка больше 50%).
Если голосование будет решено, файлы в /votes/unban могут быть удалены, все файлы для Боба в /members, /admins, /invited, /CRLs, могут быть передобавлены (или только в /devices, если это устройство, которое не запрещено) и обязаны в repo
Убрать разговор
Сохранить в convInfos removed=time::now() (как удалитьСвязь сохраняет в контактах) что разговор удаляется и синхронизируется с устройствами других пользователей
Если мы получим новое сообщение, то это будет проигнорировано.
Если Джами стартует и репо все еще присутствует, разговор не будет объявлен клиентам.
Two cases: a. If no other member in the conversation we can immediately remove the repository b. If still other members, commit that we leave the conversation, and now wait that at least another device sync this message. This avoids the fact that other members will still detect the user as a valid member and still sends new message notifications.
Когда мы уверены, что кто-то синхронизировался, удалите erased=time::now() и синхронизируйте с устройствами других пользователей
Все устройства, принадлежащие пользователю, теперь могут удалить хранилище и связанные с ним файлы
Как указать режим
Моды не могут быть изменены в течение времени. Или это другой разговор. Итак, эти данные хранятся в первоначальном сообщении об обязательстве.
{
"type": "initial",
"mode": 0,
}
На данный момент «мод» принимает значения 0 (ONE_TO_ONE), 1 (ADMIN_INVITES_ONLY), 2 (INVITES_ONLY), 3 (PUBLIC)
Processes for 1:1 swarms
Цель здесь состоит в том, чтобы сохранить старый API (addContact/removeContact, sendTrustRequest/acceptTrustRequest/discardTrustRequest) для генерации рома с одноклассным и его контактом.
Процесс все равно такой же, учетная запись может добавить контакт через addContact, а затем отправить запрос доверия через DHT. Но необходимы две изменения:
TrustRequest внедряет «conversationId», чтобы сообщить коллегам, какой разговор клонировать при принятии запроса
TrustRequest перепробованы, когда контакт возвращается в сеть. Это не так сегодня (поскольку мы не хотим генерировать новый TrustRequest, если одноклассник отбросит первый). Так что, если учетная запись получает запрос на доверие, он будет автоматически игнорироваться, если запрос с связанным разговором будет отклонен (поскольку convRequests синхронизируются)
Затем, когда контакт принимает запрос, необходимо время синхронизации, потому что контакт теперь должен клонировать разговор.
removeContact() удалит контакт и связанные с ним разговоры 1:1 (с тем же процессом, что и «Удалить разговор»). Единственное замечание здесь заключается в том, что если мы запретим контакт, мы не ждем синхронизации, мы просто удалим все связанные с ним файлы.
Сценарии сложные
Есть случаи, когда можно создать два разговора.
Алиса добавляет Боба.
Боб соглашается.
Алиса убирает Боба.
Алиса добавляет Боба.
или
Alice adds Bob and Bob adds Alice at the same time, but both are not connected together.
В этом случае создаются два разговора. Мы не хотим удалять сообщения от пользователей или выбирать один разговор здесь. Так, иногда будет показано два 1:1 рода между одними и теми же членами. Это будет генерировать некоторые ошибки во время переходного времени (как мы не хотим нарушить API, вытекающий разговор будет одним из двух показанных разговоров, но на данный момент это «ok-ish», будет исправлено, когда клиенты полностью обрабатывают разговоры ID для всех API (звоны, передача файлов и т.д.).
Важно
After accepting a conversation’s request, there is a time the daemon needs to retrieve the distant repository. During this time, clients MUST show a syncing view to give informations to the user. While syncing:
ConfigurationManager::getConversations() will return the conversation’s id even while syncing.
ConfigurationManager::conversationInfos() вернет {{«синхронизация»: «истинный»}} в случае синхронизации.
ConfigurationManager::getConversationMembers() will return a map of two URIs (the current account and the peer who sent the request).
Разговоры просят уточнения
Запросы на разговоры представлены Map<String, String> с следующими клавишами:
id: the conversation ID
from: URI of the sender
Принято: часовой печать
название: (необязательно) название разговора
описание: (необязательно)
Аватар: (необязательно)
Синхронизация профиля разговора
Для того чтобы быть идентифицируемым, разговору обычно требуются некоторые метаданные, такие как название (например, Jami), описание (например, некоторые ссылки, что такое проект и т.д.), и изображение (лого проекта).
Хранение в хранилище
Профиль разговора хранится в классическом файле vCard в корне (/profile.vcf
) например:
BEGIN:VCARD
VERSION:2.1
FN:TITLE
DESCRIPTION:DESC
END:VCARD
Синхронизация
To update the vCard, a user with enough permissions (by default: =ADMIN) needs to edit /profile.vcf
and will commit the file with the mimetype application/update-profile
.
The new message is sent via the same mechanism and all peers will receive the MessageReceived signal from the daemon.
The branch is dropped if the commit contains other files or too big or if done by a non-authorized member (by default: <ADMIN).
Последний раз
В синхронизированных данных каждое устройство отправляет другим устройствам состояние разговоров. В этом состоянии отправляется последний отображаемый. Однако, поскольку каждое устройство может иметь свое собственное состояние для каждого разговора, и, вероятно, без того же последнего обязательства в какой-то момент, есть несколько сценариев, которые следует учитывать:
Поддерживаются 5 сценариев:
если последний дисплей, отправленный другими устройствами, тот же, что и текущий, ничего не нужно делать.
если для текущего устройства не будет последнего отображения, используется удаленное отображение сообщения.
если последний удаленный файл не присутствует в репо, это означает, что коммит будет загружен позже, поэтому результат будет загружен в кеше
Если пульт уже загружен, мы проверяем, что последний локальный показал раньше в истории, чтобы заменить его
Наконец, если сообщение от одного и того же автора, это означает, что мы должны обновить последнее отображение.
Настройки
Каждый разговор имеет прикрепленные предпочтения, установленные пользователем. Эти предпочтения синхронизируются на всех устройствах пользователя. Это может быть цвет разговора, если пользователь хочет игнорировать уведомления, ограничение размера передачи файлов и т. Д. На данный момент признанные ключи:
«color» - the color of the conversation (#RRGGBB format)
«ignoreNotifications» - игнорировать уведомления о новых сообщениях в этом разговоре
«символ» - для определения дефолта эмодзи.
Эти предпочтения хранятся в пакете MapStringString, хранящемся в accountDir/conversation_data/conversationId/preferences
и отправляемых только через устройства одного и того же пользователя через SyncMsg.
API для взаимодействия с предпочтениями:
// Update preferences
void setConversationPreferences(const std::string& accountId,
const std::string& conversationId,
const std::map<std::string, std::string>& prefs);
// Retrieve preferences
std::map<std::string, std::string> getConversationPreferences(const std::string& accountId,
const std::string& conversationId);
// Emitted when preferences are updated (via setConversationPreferences or by syncing with other devices)
struct ConversationPreferencesUpdated
{
constexpr static const char* name = "ConversationPreferencesUpdated";
using cb_type = void(const std::string& /*accountId*/,
const std::string& /*conversationId*/,
std::map<std::string, std::string> /*preferences*/);
};
Управление конфликтами слияния
Поскольку два администратора могут изменять описание одновременно, конфликт слияния может возникнуть на profile.vcf
. В этом случае будет выбран commit с более высоким хэшем (например, ffffff > 000000).
API
Пользователь получил 2 способа получения и настройки метаданных разговора:
<method name="updateConversationInfos" tp:name-for-bindings="updateConversationInfos">
<tp:added version="10.0.0"/>
<tp:docstring>
Update conversation's infos (supported keys: title, description, avatar)
</tp:docstring>
<arg type="s" name="accountId" direction="in"/>
<arg type="s" name="conversationId" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="VectorMapStringString"/>
<arg type="a{ss}" name="infos" direction="in"/>
</method>
<method name="conversationInfos" tp:name-for-bindings="conversationInfos">
<tp:added version="10.0.0"/>
<tp:docstring>
Get conversation's infos (mode, title, description, avatar)
</tp:docstring>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="VectorMapStringString"/>
<arg type="a{ss}" name="infos" direction="out"/>
<arg type="s" name="accountId" direction="in"/>
<arg type="s" name="conversationId" direction="in"/>
</method>
где инфо
представляет собой map<str, str>
с следующими клавишами:
режим: только для чтения
название
описание
Аватар
Перевозить учетную запись (ссылка/экспорт)
В архиве МОЖЕ быть записана разговорная информация, чтобы можно было восстановить разговоры на новых коммитах после повторного импорта (потому что в данный момент нет приглашения).
Разговор есть, в этом случае демон способен клонировать этот разговор.
РазговорId отсутствует, поэтому демон просит (по сообщению
{{"приложение/приглашение", conversationId}}
) новое приглашение, которое пользователь должен (вновь) принять
Важно
A conversation can only be retrieved if a contact or another device is there, else it will be lost. There is no magic.
Используемые протоколы
Гит
Почему этот выбор
Each conversation will be a Git repository. This choice is motivated by:
Мы должны синхронизировать и заказывать сообщения. Древо Меркле - это идеальная структура для этого и может быть линеаризирована путем слияния ветвей. Более того, поскольку он широко используется Git, его легко синхронизировать между устройствами.
Распределенный природой, широко используемый, много задней части и подключимый.
Могли бы проверить обязательства через крюки и широко используемые крипто
При необходимости может быть сохранено в базе данных
Конфликты избегаются, используя сообщения, а не файлы.
Что мы должны подтвердить
Выступление?
git.lock
может быть низкимГрак в либгит2
Многочисленные порывы одновременно?
Ограничения
Чтобы удалить разговор, устройство должно покинуть разговор и создать другой.
Однако не постоянные сообщения (например, сообщения, которые могут быть прочитаны только на несколько минут) могут быть отправлены через специальное сообщение через DRT (например, уведомления о вводе или прочтении).
Структура
/
- invited
- admins (public keys)
- members (public keys)
- devices (certificates of authors to verify commits)
- banned
- devices
- invited
- admins
- members
- votes
- ban
- members
- uri
- uriAdmin
- devices
- uri
- uriAdmin
- unban
- members
- uri
- uriAdmin
- CRLs
Передача файлов
Сварм массово меняет передачу файлов. Теперь вся история синхронизируется, позволяя всем устройствам в разговоре легко восстановить старые файлы. Эти изменения позволяют нам перейти от логики, где отправитель толкнул файл на другие устройства, через попытку подключения к своим устройствам (это было плохо, потому что не действительно устойчиво к изменениям / неисправностям подключения и нужно было вручную перепробовать) к логике, где отправитель разрешает другим устройствам загружать.
Протокол
Отправитель добавляет в разговор новый коммит в следующем формате:
value["tid"] = "RANDOMID";
value["displayName"] = "DISPLAYNAME";
value["totalSize"] = "SIZE OF THE FILE";
value["sha3sum"] = "SHA3SUM OF THE FILE";
value["type"] = "application/data-transfer+json";
и создает ссылку в ${data_path}/conversation_data/${conversation_id}/${file_id}
где file_id=${commitid}_${value["tid"]}.${extension}
Затем получатель может загрузить файлы, связавшись с устройствами, размещающими файл, открыв канал с name="data-transfer://" + conversationId + "/" + currentDeviceId() + "/" + fileId
и хранить информацию о том, что файл ждет в ${data_path}/conversation_data/${conversation_id}/waiting
Приемник будет хранить первый открытый канал, закрывать другие и записывать в файл (с тем же путем, что и отправитель: ${data_path}/conversation_data/${conversation_id}/${file_id}
) все поступающие данные.
Когда передача завершена или канал закрыт, sha3sum проверяется, чтобы подтвердить, что файл правильный (или он удален).
В случае неудачи, когда устройство разговора будет снова в сети, мы попросим все файлы ожидания таким же образом.
Призывай ров
Идея
A swarm conversation can have multiple rendez-vous. A rendez-vous is defined by the following URI:
«accountUri/deviceId/conversationId/confId» где accountUri/deviceId описывает хост.
Хозяин может быть определен двумя способами:
В скоплении метаданных, где они хранятся как название / стол / аватар комнаты
Или первоначальный звонок.
При запуске звонка хост добавляет в ров новый обязательство, причем URI присоединяется (accountUri/deviceId/conversationId/confId).
Таким образом, каждая часть получит информацию о том, что звонок начался и сможет присоединиться к нему, позвонив ему.
Нападения?
Avoid Git bombs
Записки
Временная печать коммитации может быть доверена, потому что она редактируема.
ТЛС
Операции Git, управления сообщениями, файлами и другими вещами будут использовать p2p TLS v1.3 ссылку с только шифрами, которые гарантируют PFS.
DHT (UDP)
Используется для отправки сообщений для мобильных устройств (для запуска push-уведомлений) и для запуска TCP-соединений.
Сетевая деятельность
Процесс приглашения кого-то
Алиса хочет пригласить Боба:
Алиса добавляет Боба к разговору
Alice generates an invite: { «application/invite+json» : { «conversationId»: «$id», «members»: [{…}] }}
Две возможности для отправки сообщения a. Если не подключен, через DHT b. Иначе, Алиса отправляет по каналу SIP
Два варианта для Боба a. Принимает приглашение, сигнал высылается для клиента b. Не подключен, поэтому никогда не получит запрос, потому что Алиса не должна знать, если Боб просто проигнорировал или заблокировал Алису.
Процесс отправки сообщения кому-то
Алиса хочет отправить сообщение Бобу:
Алиса добавляет сообщение в репо, давая идентификатор
Алиса получает сообщение (от себя) если успешный
В обоих случаях создается сообщение: { «приложение/im-gitmessage-id» : «{«id»:»\(convId", "commit":"\)commitId», «deviceId»: «$alice_device_hash»}»}. а. Если не подключено, через DHT b. В противном случае, Алиса отправляет по каналу SIP
Четыре возможности для Боба: а. Боб не связан с Алисой, поэтому если он доверяет Алисе, попросите о новом соединении и отправляйтесь в b. b. Если он связан, возьмите у Алисы и объявить о новых сообщениях в. Боб не знает об этом разговоре. Просите через DHT получить приглашение сначала, чтобы иметь возможность принять этот разговор ({«приложение/приглашение», разговорId}) d. Боб отключен (нет сети, или просто закрыт). Он не получит новое сообщение, но попытается синхронизировать, когда произойдет следующее соединение
Реализация
Supported messages
Initial message
{
"type": "initial",
"mode": 0,
"invited": "URI"
}
Represents the first commit of a repository and contains the mode:
enum class ConversationMode : int { ONE_TO_ONE = 0, ADMIN_INVITES_ONLY, INVITES_ONLY, PUBLIC }
and invited
if mode = 0.
Text message
{
"type": "text/plain",
"body": "content",
"react-to": "id (optional)"
}
Or for an edition:
{
"type": "application/edited-message",
"body": "content",
"edit": "id of the edited commit"
}
Звонки
Show the end of a call (duration in milliseconds):
{
"type": "application/call-history+json",
"to": "URI",
"duration": "3000"
}
Or for hosting a call in a group (when it starts)
{
"type": "application/call-history+json",
"uri": "host URI",
"device": "device of the host",
"confId": "hosted confId"
}
A second commit with the same JSON + duration
is added at the end of the call when hosted.
Добавить файл
{
"type": "application/data-transfer+json",
"tid": "unique identifier of the file",
"displayName": "File name",
"totalSize": "3000",
"sha3sum": "a sha3 sum"
}
totalSize
is in bits,
Updating profile
{
"type": "application/update-profile",
}
Member event
{
"type": "member",
"uri": "member URI",
"action": "add/join/remove/ban"
}
When a member is invited, join or leave or is kicked from a conversation
Vote event
Generated by administrators to add a vote for kicking or un-kicking someone.
{
"type": "vote",
"uri": "member URI",
"action": "ban/unban"
}
!! Старый проект!!
Примечание
Following notes are not organized yet. Just some line of thoughts.
Улучшения крипто.
Для серьезной групповой чата нам также нужна серьезная крипто. При текущем дизайне, если сертификат украден как предыдущие значения DHT разговора, разговор может быть расшифрован. Может быть, нам нужно пойти на что-то вроде Double ratchet.
Примечание
A lib might exist to implement group conversations.
Необходимость поддержки ЭКК в OpenDHT
Использование
Добавить роли?
Есть два основных случая использования групповых чатов:
Что-то вроде Mattermost в компании, с частными каналами, и некоторыми ролями (админ/спектактор/бот/т.д.) или для образования (где только несколько действуют).
Горизонтальные разговоры, как разговоры между друзьями.
Jami will be for which one?
Идея реализации
Сертификат для группы, которая подписывает пользователя флагом для роли.
Присоединяйтесь к разговору
Только по прямому приглашению
С помощью ссылки/КР-код/что угодно
Через имя комнаты?
Что нам нужно
Конфиденциальность: члены вне группового чата не должны иметь возможность читать сообщения в группе
Конфиденциальность: если какой-либо ключ группы был взломан, предыдущие сообщения должны оставаться конфиденциальными (по возможности)
Заказы сообщений: необходимо иметь сообщения в правильном порядке
Синхронизация: Также необходимо убедиться, что все сообщения будут доступны как можно скорее.
Продолжительность: На самом деле сообщение на DHT проходит всего 10 минут. Поскольку это лучшее время, рассчитанное для этого типа DHT. Чтобы сохранить данные, узел должен переставлять значение на DHT каждые 10 минут. Другой способ сделать, когда узел не работает, это позволить узлам переставлять данные. Но если через 10 минут 8 узлов все еще здесь, они будут выполнять 64 запроса (и это экспоненциально).
Другие распределенные способы
IPFS: Нужно провести расследование
Мне нужно провести расследование
Мне нужно провести расследование.
На основании текущей работы, которую мы имеем
Групповой чат может быть основан на той же работе, что и для многоустройств (но здесь, с групповым сертификатом).
Это должно переместить базу данных с клиента в демона.
Если никто не подключен, синхронизация не может быть сделана, и человек никогда не увидит разговор
Еще один DHT
Как DHT с суперпользователем.
Передача файлов
В настоящее время алгоритм передачи файлов основан на соединении TURN (см. Передача файлов). В случае большой группы это будет плохо.
Другая проблема: в настоящее время нет внедрения поддержки TCP для ICE в PJSIP. Это обязательно для этого момента (в pjsip или домашних изготовлениях)
Ресурсы
https://eprint.iacr.org/2017/666.pdf
Устойчивая распределенная синхронизация сетевых линейных систем с промежуточной информацией (Сен Филлипс и Рикардо Г. Санфелис)