무더기

A swarm (group chat) is a set of participants capable of resilient, decentralized communication. For example, if two participants lose connectivity with the rest of the group (e.g., during an Internet outage) but can still reach each other over a LAN or subnetwork, they can exchange messages locally and then synchronize with the rest of the group once connectivity is restored.

A swarm is defined by the following properties:

  1. Ability to split and merge based on network connectivity.

  2. History synchronization. Every participant must be able to send a message to the entire group.

  3. 중앙 권한이 없고 서버를 신뢰할 수 없습니다.

  4. Non-repudiation. Devices must be able to verify past messages’ validity and to replay the entire history.

  5. Perfect Forward Secrecy (PFS) is provided on the transport channels. Storage is handled by each device.

주요 아이디어는 참가자들과 동기화된 메르클 나무를 만드는 것입니다.

We identified four modes for swarms that we want to implement:

  • ONE_TO_ONE: A private conversation between two endpoints—either between two users or with yourself.

  • ADMIN_INVITES_ONLY: A swarm in which only the administrator can invite members (for example, a teacher-managed classroom).

  • INVITES_ONLY: A closed swarm that admits members strictly by invitation; no one may join without explicit approval.

  • PUBLIC: A public swarm that anyone can join without prior invitation (For example a forum).

시나리오

무리를 만들

Bob wants to create a new swarm

  1. Bob creates a local Git repository.

  2. 다음으로, 그는 다음과 같은 첫 번째 서명된 약속을 만듭니다:

    • /admins에 공개된 열쇠

    • ̀ / 기기 에 있는 장치 인증서

    • 그의 CRL는 ̀ /crls`

  3. 첫 번째 컴티드의 해시가 대화의 아이디가 됩니다.

  4. Bob announces to his other devices that he created a new conversation. This is done via an invite to join the group sent through the DHT to other devices linked to that account.

누군가 추가

Bob adds Alice

  1. Bob adds Alice to the repo:

    • /invited로 초대된 URI를 추가합니다

    • CRL를 /crls로 추가한다

  2. Bob sends a request on the DHT.

초대 을 받는 것

Alice gets the invite to join the previously created swarm

  1. Alice accepts the invite (if she declines, nothing happens; she will remain in the “invited” list, and will never receive any messages)

  2. A peer-to-peer connection is established between Alice and Bob.

  3. Alice pulls the Git repository from Bob. WARNING this means that messages require a connection, not from the DHT as it is today.

  4. Alice validates the commits from Bob.

  5. To validate that Alice is a member, she removes the invite from /invited directory, then adds her certificate to the /members directory

  6. Once all commits are validated and syncronized to her device, Alice discovers other members of the group. with these peers, she will then construct the DRT with Bob as a bootstrap.

메시지를 보내는 것

Alice sends a message to Bob

  1. Alice creates a commit message. She constructs a JSON payload containing the MIME type and message body. For example:

{
    "type": "text/plain",
    "body": "hello"
}
  1. Alice ensure her device credentials are present. If Alice’s device certificate or its associated CRL isn’t already stored in the repository, she adds them so that other participants can verify the commit.

  2. Alice commits to the repository (Because Jami relies primarily on commit-message metadata rather than file contents, merge conflicts are rare; the only potential conflicts would involve CRLs or certificates, which are versioned in a dedicated location).

  3. Alice announces the commit via the DRT with a service message and pings the DHT for mobile devices (they must receive a push notification).

참고

To notify other devices, the sender transmits a SIP message with type: application/im-gitmessage-id. The JSON payload includes the deviceId (the sender’s), the conversationId and the reference (hash) of the new commit.

메시지 수신

Bob receives a message from Alice

  1. Bob performs a Git pull on Alice’s repository.

  2. All incoming commits MUST be verified by a hook.

  3. If all commits are valid, commits are stored and displayed.Bob then announces the message via the DRT for other devices.

  4. If any commit is invalid, pull is aborted. Alice must restore her repository to a correct state before retrying.

공약의 유효성 확인

사용자가 원치 않는 컴밋 (충돌, 거짓 메시지 등) 을 밀어 넣지 않기 위해, 각 컴밋 (최고의 종목에서 가장 최신 종목) 은 원격 지부를 통합하기 전에 검증되어야 합니다.

참고

  1. 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.

  2. If a fetch is too big, it’s not merged.

  • For each incoming commit, ensure that the sending device is currently authorized and that the issuer’s certificate exists under /members or /admins, and the device’s certificate under /devices.

  • Then handle one of three cases, based on the commit’s parent count:

    • Merge Commit (2 parents). No further validation is required, merges are always accepted.

    • Initial Commit (0 parents). Validate that this is the very first repository snapshot:

      • Admin certificate is added.

      • Device certificate is added.

      • CRLs (Certificate Revocation Lists) are added.

      • No other files are present.

    • Ordinary Commit (1 parent). The commit message must be JSON with a top‑level type field. Handle each type as follows:

      • If text (or any non–file‑modifying MIME type)

        • Signature is valid against the author’s certificate in the repo.

        • No unexpected files are added or removed.

      • If vote

        • voteType is one of the supported values (e.g. “ban”, “unban”).

        • The vote matches the signing user.

        • The signer is an admin, their device is present, and not themselves banned.

        • No unexpected files are added or removed.

      • If member

        • If adds

          • Properly signed by the inviter.

          • New member’s URI appears under /invited.

          • No unexpected files are added or removed.

          • If ONE_TO_ONE, ensure exactly one admin and one member.

          • If ADMIN_INVITES_ONLY, the inviter must be an admin.

        • If joins

          • Properly signed by the joining device.

          • Device certificate added under /devices.

          • Corresponding invite removed from /invited and certificate added to /members.

          • No unexpected files are added or removed.

        • If banned

          • Vote is valid per the vote rules above.

          • Ban is issued by an admin.

          • Target’s certificate moved to /banned.

          • Only files related to the ban vote are removed.

          • No unexpected files are added or removed.

      • Fallback. If the commit’s type or structure is unrecognized, reject it and notify the peer (or user) that they may be running an outdated version or attempting unauthorized changes.

기기를 금지

중요

Jami source code tends to use the terms (un)ban, while the user interface uses the terms (un)block.

Alice, Bob, Carla, Denys are in a swarm. Alice issues a ban against Denys.

In a fully peer‑to‑peer system with no central authority, this simple action exposes three core challenges:

  1. Untrusted Timestamps: Commit timestamps cannot be relied upon for ordering ban events, as any device can forge or replay commits with arbitrary dates.

  2. Conflicting bans: In cases where multiple admin devices exist, network partitions can result in conflicting ban decisions. For instance, if Alice can communicate with Bob but not with Denys and Carla, while Carla can communicate with Denys, conflicting bans may occur. If Denys bans Alice while Alice bans Denys, the group’s state becomes unclear when all members eventually reconnect and merge their conversation histories.

  3. Compromised or expired devices: Devices can be compromised, stolen, or have their certificates expire. The system must allow banning such devices and ensure they cannot manipulate their certificate or commit timestamps to send unauthorized messages or falsify their expiration status.

비슷한 시스템 (분산 그룹 시스템) 은 그리 많지 않지만, 이것들은 몇 가지 예입니다.

  • [mpOTR는 누군가를 금지하는 방법을 정의하지 않습니다]

  • 그룹 채팅의 중앙 서버가 없는 신호는 그룹에서 누군가를 금지할 수 있는 능력을 제공하지 않습니다.

This voting system needs a human action to ban someone or must be based on the CRLs info from the repository (because we can not trust external CRLs).

대화 중 장치 를 제거

이 부분은 대화의 분열을 피하기 위해 합의를 해야 할 유일한 부분입니다. 예를 들어, 두 명의 구성원들이 대화에서 서로를 다면, 세 번째가 어떤 모습으로 나타납니다?

이 방법은 취소된 장치를 감지하거나, 공공장소에서 원치 않는 사람들을 모집하지 않도록 하는 데 필요합니다.

Alice removes Bob

중요

Alice MUST be an admin to vote.

  • 먼저, 그녀는 밥을 금지하는 것에 찬성하고, 이를 위해, 그녀는 /votes/ban/members/uri_bob/uri_alice (원들을 장치에 대한 장치로 교체하거나, 초대 또는 관리자를 위해 초대하거나,

  • 그리고 그녀는 투표가 해결되었는지 확인합니다. 이것은 50% 이상의 관리자가 밥을 금지하기로 동의한다는 것을 의미합니다 (그녀가 혼자 있다면, 그것은 50% 이상입니다).

  • 투표가 해결되면 /votes/ban에 있는 파일들은 삭제될 수 있고, /members, /admins, /invited, /CRL, /device의 Bob의 모든 파일들은 삭제될 수 있습니다. (또는 금지된 장치라면 /device에서만) 그리고 Bob의 인증서는 /banned/members/bob_uri.crt (또는 /banned/devices/uri.crt, 장치가 금지된 경우) 에 배치되어 repo에 배포될 수 있습니다.

  • 그 다음, 앨리스는 다른 사용자들에게 (보브 이외)

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, /CRL에 있는 Bob의 모든 파일들은 다시 추가될 수 있습니다.

대화 를 제거

  1. convInfos에서 저장하여 제거=시간::지금() (removeContact는 연락처에서 저장하는 것과 같이) 대화가 제거되고 다른 사용자의 장치와 동기화됩니다

  2. 이 대화에 대한 새로운 약속이 수신되면 무시됩니다

  3. 자미가 시작해서 리포가 여전히 존재한다면, 대화는 고객에게 알려지지 않습니다.

  4. 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.

  5. 누군가가 동기화되었는지 확실하게 알 때, 삭제된=time::now() 를 제거하고 다른 사용자의 장치와 동기화하십시오

  6. 이제 사용자의 소유의 모든 장치가 저장소 및 관련 파일을 삭제할 수 있습니다

모드를 지정하는 방법

모드는 시간에 따라 변경될 수 없습니다. 또는 다른 대화입니다. 그래서, 이 데이터는 초기 약속 메시지에서 저장됩니다. 약속 메시지는 다음과 같습니다:

{
    "type": "initial",
    "mode": 0,
}

현재 “모드”는 값 0 (ONE_TO_ONE), 1 (ADMIN_INVITES_ONLY), 2 (INVITES_ONLY), 3 (PUBLIC) 를 수용합니다

Processes for 1:1 chats

The goal here is to keep the old API (addContact/removeContact, sendTrustRequest/acceptTrustRequest/discardTrustRequest) to create a chat with a peer and its contact. This still implies some changes that we cannot ignore:

프로세스는 여전히 동일합니다. 계정에서는 addContact을 통해 연락처를 추가하고 DHT를 통해 신뢰 요청을 보낼 수 있습니다. 그러나 두 가지 변경 사항이 필요합니다:

  1. TrustRequest는 “회담Id”를 삽입하여 피어에게 요청을 받아들이는 동안 어떤 대화를 복제해야 하는지 알려줍니다.

  2. 트러스트레이스트는 연락이 다시 온라인에 올 때 다시 시도됩니다. 오늘날은 그렇지 않습니다 (동생이 첫 번째를 폐기하면 새로운 트러스트레이스트를 생성하고 싶지 않기 때문입니다). 따라서, 계정이 신뢰 요청을 받으면, 관련 대화와 관련된 요청이 거부되면 자동으로 무시됩니다 ( convRequests가 동기화됨에 따라)

그런 다음 연락처가 요청을 받아들일 때 동기화 기간이 필요하죠. 왜냐하면 연락처가 이제 대화를 복제해야 하기 때문입니다.

removeContact() 는 연락처 및 관련 1:1 대화 (연결을 제거하는 것과 같은 프로세스) 를 제거합니다. 여기서 유일한 메모는 연락처를 금지하면 동기화를 기다릴 수 없습니다. 우리는 모든 관련 파일을 제거합니다.

어려운 시나리오

두 가지 대화가 가능한 경우도 있습니다. 이 경우 적어도 두 가지 상황입니다.

  1. Alice adds Bob.

  2. Bob accepts.

  3. Alice removes Bob.

  4. Alice adds Bob.

또는

  1. Alice adds Bob and Bob adds Alice at the same time, but both are not connected together.

In this case, two conversations are generated. We don’t want to remove messages from users or choose one conversation here. So, sometimes two conversations between the same members will be shown. It will generate some bugs during the transition time (as we don’t want to break API, the inferred conversation will be one of the two shown conversations, but for now it’s “ok-ish”, will be fixed when clients will fully handle conversationId for all APIs (calls, file transfer, etc)).

중요

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

  • 수신: 시간표

  • 제목: 대화의 이름 (선택)

  • 설명: (선택)

  • avatar: (optional) the profile picture

대화 프로필 동기화

대화가 식별될 수 있도록 일반적으로 제목 (예: 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가지 시나리오가 지원됩니다.

  • 다른 장치에서 전송된 마지막 디스플레이가 현재와 동일하다면, 아무것도 할 수 없습니다.

  • 현재 장치에 대한 마지막 표시가 없다면 원격으로 표시된 메시지가 사용됩니다.

  • 마지막으로 표시된 원격이 repo에 존재하지 않는다면, 그것은 나중에 컴백이 가져온 것을 의미합니다, 따라서 결과를 캐시

  • 원격이 이미 가져온 경우, 우리는 로컬 마지막 표시 된 역사에서 이전인지 확인하여 그것을 대체합니다

  • 마지막으로 같은 작가의 메시지가 발표되면 마지막 표시된 메시지를 업데이트해야 한다는 것을 의미합니다.

우선순위

모든 대화에는 사용자가 설정한 선호도가 첨부되어 있습니다. 이러한 선호도는 사용자의 장치에 걸쳐 동기화됩니다. 사용자가 알림을 무시하고 파일 전송 크기의 제한을 원하지 않으면 대화의 색상이 될 수 있습니다. 현재로서는 인식되는 키는 다음과 같습니다.

  • “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에서 융합 충돌이 발생할 수 있습니다. 이 경우 더 높은 해시 (예를 들어 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>

info는 다음 키가 있는 map<str, str>입니다:

  • 모드: 읽기만

  • 제목

  • 설명

  • avatar: the profile picture

사용된 프로토콜

Git

왜 이런 선택을 했을까요?

Each conversation will be a Git repository. This choice is motivated by:

  1. 우리는 메시지를 동기화하고 순서대로 해야 합니다. 메르클 트리는 이를 위해 완벽한 구조이며 분자를 합쳐서 선형화 할 수 있습니다. 게다가, Git에서 대량으로 사용되기 때문에, 장치들 사이에서 동기화하기가 쉽습니다.

  2. 자연에 의해 분산되어 있고, 많이 사용되고, 많은 백엔드와 플러그 가 가능해

  3. 해킹 및 대량으로 사용되는 암호화폐를 통해 약속을 확인할 수 있습니다

  4. 필요하다면 데이터베이스에 저장할 수 있습니다

  5. 갈등은 파일이 아닌 컴백 메시지를 사용하여 피됩니다.

우리가 확인해야 할 것은

  • 성능은 낮을 수 있습니다.

  • libgit2에 있는 해킹

  • 동시에 여러 번?

제한

역사서는 삭제될 수 없습니다. 대화를 삭제하려면 장치가 대화를 떠나 다른 대화를 만들어야 합니다.

그러나 영구적이지 않은 메시지 (예컨대 몇 분 동안만 읽을 수 있는 메시지) 는 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

파일 전송

This new system overhauls file sharing: the entire history is now kept in sync, so any device in the conversation can instantly access past files. Rather than forcing the sender to push files directly—an approach that was fragile in the face of connection drops and often required manual retries—devices simply download files when they need them. Moreover, once one device has downloaded a file, it can act as a host for others, ensuring files remain available even if the original sender goes offline.

프로토콜

송신자는 다음 형식으로 대화에 새로운 컴백을 추가합니다:

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}에서 링크를 생성합니다.

다음, 수신자는 이제 name="data-transfer://" + conversationId + "/" + currentDeviceId() + "/" + fileId로 채널을 열고 파일을 호스트하는 장치와 연락하여 파일을 다운로드 할 수 있으며 ${data_path}/conversation_data/${conversation_id}/waiting

연결을 수신하는 장치는 파일을 전송할 수 있는지 확인함으로써 채널을 수용합니다. sha3sum이 올바르고 파일이 존재하는지 확인합니다. 수신자는 첫 번째 채널을 열고 다른 채널을 닫고 파일에 입력합니다.

전송이 완료되거나 채널이 닫힌 경우 sha3sum가 파일의 정확성을 확인합니다. 유효하다면 파일은 대기 중에서 제거됩니다.

실패의 경우 대화의 장치가 다시 온라인에 들어가면, 우리는 동일한 방식으로 모든 대기 파일을 요청합니다.

Call in Swarm

아이디어

A swarm conversation can have multiple rendez-vous. A rendez-vous is defined by the following URI:

“accountUri/deviceId/conversationId/confId”는 accountUri/deviceId가 호스트를 설명하는 경우입니다.

호스트는 두 가지 방법으로 결정될 수 있습니다.

  • In the swarm metadatas. Where it’s stored like the title/desc/avatar (profile picture) of the room

  • 혹은 처음 전화를 걸었던 사람

When starting a call, the host will add a new commit to the repository, with the URI to join (accountUri/deviceId/conversationId/confId). This will be valid till the end of the call (announced by a commit with the duration to show)

그래서 모든 구성원들은 전화가 시작됐다는 정보를 받고 전화로 가입할 수 있습니다.

공격?

  • Avoid Git bombs

참고

컴백의 타임 스탬프는 편집이 가능하기 때문에 신뢰할 수 있습니다. 사용자의 타임 스탬프만 신뢰할 수 있습니다.

TLS

Git 운영, 제어 메시지, 파일 등은 P2p TLS v1.3 링크를 사용하여 PFS를 보장하는 암호만 사용합니다. 따라서 각 키는 새로운 연결에 대해 재협상됩니다.

DHT (UDP)

모바일 (Push Notifications) 를 실행하고 TCP 연결을 시작하기 위해 사용된다.

네트워크 활동

초대하는 과정

앨리스가 밥을 초대하고 싶어

  1. 앨리스가 밥을 대화에 더해줍니다

  2. Alice generates an invite: { “application/invite+json” : { “conversationId”: “$id”, “members”: [{…}] }}

  3. A. 연결되지 않은 경우 DHT b. 그렇지 않으면, 앨리스는 SIP 채널에서 전송합니다

  4. Bob a: 초청을 수신하면 클라이언트 b: 연결되지 않아서 요청을 수신하지 않습니다. 앨리스는 앨리스를 무시하거나 차단했는지 알 수 없습니다. 유일한 방법은 새로운 메시지를 통해 새로운 초청을 재생하는 것입니다.

누군가에게 메시지를 보내는 프로세스

앨리스가 밥에게 메시지를 보내고 싶어

  1. 앨리스가 레포에 메시지를 추가하고 신분증을

  2. 앨리스는 성공하면 메시지를 받습니다.

  3. 2가지 가능성은, alice와 bob가 연결되어 있거나 그렇지 않습니다. 두 경우 모두 메시지가 생성됩니다: { ” 응용 프로그램/ im-git-message-id ” : “{“id “:” \( convId ", " 약속 ":" \) commitId “, ” 장치Id “: ” $ alice_device_hash “} “}. a. 연결되지 않으면 DHT b를 통해 Alice가 SIP 채널에 전송합니다.

  4. 밥은 앨리스와 연결되지 않으므로 앨리스에 신뢰를 가지고 있다면 새로운 연결을 요청하고 b로 이동하십시오. 연결되면 앨리스에서 가져와 새로운 메시지를 발표하십시오. 밥은 그 대화를 알지 못합니다. DHT를 통해 초대서를 먼저 요청하여 대화를 받아들일 수 있습니다.

시행

[아차그램: 스와어 채팅 클래스]

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.

Add a file

{
    "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에서 ECC 지원이 필요합니다

사용

역할 추가?

그룹 채팅의 두 가지 주요 사용 사례가 있습니다.

  1. 회사에서 사적 채널과 일부 역할 (관리자/관객/봇/등) 또는 교육 (일반적으로 몇 명이 활동하는 곳) 같은

  2. 지평적인 대화는 친구들 사이의 대화처럼요.

Jami will be for which one?

실행 아이디어

역할에 대한 깃발을 표시하는 사용자에 대한 인증서. 추가 또는 취소도 수행 할 수 있습니다.

대화에 참여

  • 직접 초청을 통해서만

  • 링크/QR 코드/무엇이든

  • 방 이름으로?

우리가 필요로 하는 것

  • 비밀: 그룹 채팅 외부의 회원은 그룹 내 메시지를 읽을 수 없어야 합니다

  • 비밀: 그룹에서 어떤 키가 손상되면 이전 메시지는 비밀로 유지되어야 합니다 (가능한 한)

  • 메시지 순서: 메시지가 올바른 순서로 있어야 합니다

  • 동기화: 또한 모든 메시지가 가능한 한 빨리 전달되도록 해야 합니다.

  • 지속성: 실제로 DHT에 있는 메시지는 10분만 지속된다. 왜냐하면 이것은 이러한 DHT에 대한 가장 좋은 계산 시간이기 때문입니다. 데이터를 지속하기 위해 노드는 10분마다 DHT에 대한 값을 다시 설정해야 합니다. 노드가 오프라인 상태에서 수행 할 수있는 또 다른 방법은 노드가 데이터를 다시 입력하도록 허용하는 것입니다. 그러나 10분 후에 8개의 노드가 여전히 여기에 있다면 64개의 요청을 수행합니다. (이 기하급수적입니다). 그 동안 스팸을 피하는 현재의 방법은 쿼리입니다. 이것은 여전히 64개의 요청을 수행하지만 최대 과잉을 8개의 노드로 제한합니다.

다른 분산 방식

  • IPFS: 좀 조사해야 합니다

  • 좀 더 조사해야 해요

  • 조사가 필요해요

현재 우리가 하고 있는 일에 따라

그룹 채팅은 이미 멀티 디바이스에 대한 동일한 작업에 기초할 수 있습니다.

  1. 이 데이터베이스를 클라이언트에서 데이몬으로 옮길 필요가 있습니다

  2. 연결된 사람이 없다면 동기화가 불가능하며, 대화는 절대로 볼 수 없습니다.

또 다른 DHT

DHT가 슈퍼 사용자처럼

What’s next for file transfers

Currently, the file transfer algorithm is based on a TURN connection (See 파일 전송). In the case of a big group, this will be bad. We first need a P2P connection for the file transfer. Implement the RFC for P2P transfer.

Other problem: currently there is no implementation for TCP support for ICE in PJSIP. This is mandatory for this point (in PJSIP or homemade)

자원