السحابة
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:
Ability to split and merge based on network connectivity.
History synchronization. Every participant must be able to send a message to the entire group.
لا يوجد سلطة مركزية لا يمكن الاعتماد على أي خادم
Non-repudiation. Devices must be able to verify past messages' validity and to replay the entire history.
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 creates a local Git repository.
ثم يقوم بإنشاء تعهد أولى وقع مع ما يلي:
مفتاحه العام في
/admins
شهادة الجهاز في ̀ /جهازات `
كRL في ̀ /crls`
الهاشش من أول التزام يصبح ** ID ** من المحادثة
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
Bob adds Alice to the repo:
يضيف الرقم البياني المشارك في
/invited
يضيف الـ CRL إلى
/crls
Bob sends a request on the DHT.
تلقي دعوة
Alice gets the invite to join the previously created swarm
Alice accepts the invite (if she declines, nothing happens; she will remain in the "invited" list, and will never receive any messages)
A peer-to-peer connection is established between Alice and Bob.
Alice pulls the Git repository from Bob. WARNING this means that messages require a connection, not from the DHT as it is today.
Alice validates the commits from Bob.
To validate that Alice is a member, she removes the invite from
/invited
directory, then adds her certificate to the/members
directoryOnce 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
Alice creates a commit message. She constructs a JSON payload containing the MIME type and message body. For example:
{
"type": "text/plain",
"body": "hello"
}
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.
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).
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
Bob performs a Git pull on Alice's repository.
All incoming commits MUST be verified by a hook.
If all commits are valid, commits are stored and displayed.Bob then announces the message via the DRT for other devices.
If any commit is invalid, pull is aborted. Alice must restore her repository to a correct state before retrying.
تأكيد التزامات
لتجنب استخدام المستخدمين لتحقيق بعض المشاركات غير المرغوب فيها (مع الصراعات والرسائل الكاذبة، إلخ) ، هذا هو كيفية تأكيد كل مشاركة (من أقدم إلى أحدث) يجب قبل دمج فرع بعيد:
ملاحظة
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.
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 eachtype
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:
Untrusted Timestamps: Commit timestamps cannot be relied upon for ordering ban events, as any device can forge or replay commits with arbitrary dates.
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.
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 لا تعريف كيفية حظر شخص ما]https://www.cypherpunks.ca/~iang/pubs/mpotr.pdf)
الإشارة، بدون أي خادم مركزي للردشة الجماعية (إديت: تغيروا هذا النقطة مؤخراً) ، لا تعطي القدرة على منع شخص من مجموعة.
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 MUST be an admin to vote.
أولاً، تصوت لصالح حظر بوب. لفعل ذلك، تقوم بإنشاء الملف في /votes/ban/members/uri_bob/uri_alice (يمكن استبدال الأعضاء بأجهزة لجهاز، أو دعوة لدعوات أو إدارة للمدراء)
ثم تتحقق من أن التصويت قد تم حلاله، وهذا يعني أن > 50% من المدراء يوافقون على حظر بوب (إذا كانت وحدها، فمن المؤكد أن هذا أكثر من 50%).
إذا تم حل التصويت، يمكن إزالة الملفات في /votes/ban، ويمكن إزالة جميع الملفات لـ Bob في /members، /admins، /invited، /CRLs، /devices (أو فقط في /devices إذا كان جهاز محظور) ويمكن وضع شهادة 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، وجميع الملفات لـ Bob في /members، /admins، /invited، /CRLs، يمكن إعادة إضافتها (أو فقط في /جهازات إذا كان جهاز غير محظور) ولتزويدها إلى 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.
عندما نكون متأكدين من أن شخص ما تم مزامنة، إزالة ممسح=وقت::الآن() ومزامنة مع أجهزة المستخدم الآخرين
جميع الأجهزة المملوكة للمستخدم يمكنها الآن حذف مخزن الملفات والملفات ذات الصلة
كيفية تحديد وضع
لا يمكن تغيير الأوضاع عبر الزمن. أو أنها محادثة أخرى. لذلك، يتم تخزين هذه البيانات في رسالة التزام الأولي. رسالة التزام سيكون على النحو التالي:
{
"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. ولكن هناك حاجة إلى تغييرين:
يضم TrustRequest "محادثةId" لإعلام الأقران ما هو المحادثة التي يجب أن يتم نسخها عند قبول الطلب
يتم إعادة محاولة TrustRequest عندما يعود الاتصال على الإنترنت. هذا ليس هو الحال اليوم (لأننا لا نريد إنشاء TrustRequest جديد إذا رفض النظير الأول). لذلك ، إذا تلقى حساب طلب الثقة ، فسيتم تجاهله تلقائيا إذا تم رفض الطلب مع محادثة ذات صلة (كما يتم مزامنة convRequests)
ثم، عندما يقبل الاتصال الطلب، فمن الضروري أن يكون هناك فترة من التزام المزامن، لأن الاتصال الآن يحتاج إلى نسخ المحادثة.
إزالةContact() سوف يزيل الاتصال والمحادثات ذات الصلة 1: 1 (مع نفس العملية التي "إزالة المحادثة"). ملاحظة الوحيدة هنا هي أنه إذا حظرنا الاتصال ، فنحن لا ننتظر التزام المزامنة ، نحن فقط إزالة جميع الملفات ذات الصلة.
سيناريوهات صعبة
هناك بعض الحالات التي يمكن فيها إنشاء محادثتين، هذه على الأقل اثنتين من تلك السيناريوهات:
Alice adds Bob.
Bob accepts.
Alice removes Bob.
Alice adds Bob.
أو
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).
المحادثات تطلب تحديد
يتم تمثيل طلبات المحادثات بواسطة ** خريطة<خطوط، خطوط>** مع المفاتيح التالية:
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).
آخر عرض
في البيانات المزامنة ، يرسل كل جهاز إلى أجهزة أخرى حالة المحادثات. في هذه الحالة ، يتم إرسال آخر عرض. ومع ذلك ، لأن كل جهاز يمكن أن يكون له حالة خاصة لكل محادثة ، وربما دون نفس الالتزام الأخير في وقت ما ، هناك العديد من السيناريوهات التي يجب مراعاةها:
يتم دعم خمسة سيناريوهات:
إذا كانت آخر عرض تم إرساله من قبل أجهزة أخرى هو نفس الجهاز الحالي، لا يوجد شيء يمكن القيام به.
إذا لم يكن هناك آخر عرض للجهاز الحالي، يتم استخدام الرسالة المعروضة عن بعد.
إذا كان جهاز التحكم عن بعد آخر عرض ليس موجودا في repo ، فهذا يعني أن التوصيل سيتم الحصول عليه في وقت لاحق ، لذلك تخزين النتيجة
إذا تم الحصول على جهاز التحكم عن بعد بالفعل ، فإننا نتحقق من أن المحلي الأخير المعرض هو قبل في التاريخ لاستبداله
أخيراً إذا تم الإعلان عن رسالة من نفس المؤلف، فهذا يعني أننا بحاجة إلى تحديث آخر رسالة عرضت.
التفضيلات
كل محادثة تضم تفضيلات محددة من قبل المستخدم. يتم مزامنة هذه التفضيلات عبر أجهزة المستخدم. يمكن أن يكون هذا لون المحادثة ، إذا أراد المستخدم تجاهل الإشعارات ، ومحدد حجم نقل الملفات ، إلخ.
"color" - the color of the conversation (#RRGGBB format)
"تجاهل الإخطارات" - تجاهل الإخطارات عن الرسائل الجديدة في هذه المحادثة
"رمز" - لتعريف إيموجي افتراضي.
يتم تخزين هذه التفضيلات في حزمة MapStringString، وتخزينها في accountDir/conversation_data/conversationId/preferences
وتتم إرسالها فقط عبر أجهزة نفس المستخدم عبر SyncMsg.
إن إطار إطار التفاعل مع التفضيلات هو:
// 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
. في هذه الحالة ، سيتم اختيار التزام مع hash الأعلى (مثل ffffff > 000000).
إدارة الطاقة
المستخدم حصل على طريقتين للحصول على وتعيين بيانات المحادثة:
<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
إعادة استيراد حساب (رابط/صادرة)
يجب أن يحتوي الملف على conversationId لكي يتمكن من استرداد المحادثات على المشاركات الجديدة بعد إعادة الاستيراد (لأن لا يوجد دعوة في هذه المرحلة). إذا جاء المشاركة لمحادثة غير موجودة هناك إمكانات:
المحادثة موجودة، في هذه الحالة، الديمون قادر على إعادة تقليد هذه المحادثة
المحادثة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
يمكن أن يكون منخفضاالكوكب في 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}
حيث file_id=${commitid}_${value["tid"]}.${extension}
ثم، يمكن للمستلم الآن تنزيل الملفات عن طريق الاتصال بالأجهزة التي تستضيف الملف عن طريق فتح قناة مع name="data-transfer://" + conversationId + "/" + currentDeviceId() + "/" + fileId
وتخزين المعلومات التي تنتظر الملف في ${data_path}/conversation_data/${conversation_id}/waiting
سيتقبل الجهاز الذي يتلقى الاتصال القناة عن طريق التحقق من إمكانية إرسال الملف (إذا كان sha3sum صحيحًا وإذا كان الملف موجودًا). سيحافظ المستلم على القناة الأولى المفتوحة، ويقفل الآخرين ويكتب في ملف (مع نفس المسار الذي يستخدمه المرسل: ${data_path}/conversation_data/${conversation_id}/${file_id}
) جميع البيانات الموصلة.
عندما يتم الانتهاء من النقل أو إغلاق القناة، يتم التحقق من أن الملف صحيح (إلا يتم حذفها). إذا كان صالحًا، سيتم إزالة الملف من انتظار.
في حالة فشل، عندما يعود جهاز المحادثة على الإنترنت، سنطلب جميع ملفات الانتظار بنفس الطريقة.
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
ملاحظات
يمكن الوثوق بخط زمني لالتزام لأنه قابل للتحرير. يمكن الوثوق فقط بخط زمني للمستخدم.
التلفزيون
عمليات Git ، رسائل التحكم ، الملفات ، وغيرها من الأشياء ستستخدم رابط P2p TLS v1.3 مع شفرات فقط التي تضمن PFS. لذلك يتم إعادة التفاوض على كل مفتاح لكل اتصال جديد.
DHT (UDP)
يستخدم لإرسال رسائل للجوال (لتفعيل إشعارات دفع) وإطلاق اتصال TCP.
نشاط الشبكة
عملية دعوة شخص ما
(أليس) تريد دعوة (بوب)
أليس تضيف بوب إلى محادثة
Alice generates an invite: { "application/invite+json" : { "conversationId": "$id", "members": [{...}] }}
إمكانات إرسال الرسالة a. إذا لم تكن متصلة، عبر DHT b. وإلا، Alice يرسل على قناة SIP
إمكانات لـ بوب a. يتلقى الدعوة، يتم إصدار إشارة للعميل b. غير متصل، لذلك لن تتلقى الطلب أبدا لأن أليس لا يجب أن تعرف إذا كان بوب تجاهل أو حظر أليس. الطريقة الوحيدة هي إعادة تشكيل دعوة جديدة عن طريق رسالة جديدة (انظر السيناريو التالي)
عملية لإرسال رسالة لشخص ما
(أليس) تريد إرسال رسالة إلى (بوب):
أليس تضيف رسالة في الردود، وتعطى هوية
Alice تتلقى رسالة (من نفسها) إذا نجحت
إمكانات اثنين، أليس وبوب متصلة، أو لا. في كلتا الحالتين يتم إنشاء رسالة: { "التطبيق/im-gitmessage-id" : "{"id":"\(convId"، "التزام":"\)commitId"، "deviceId": "$alice_device_hash"}"}.
أربعة إمكانيات لـ بوب: a. بوب ليس متصلًا بـ أليس، لذا إذا كان يثق في أليس، اطلب اتصالًا جديدًا واذهب إلى b. b. إذا كان متصلًا، احضر من أليس وإعلان رسائل جديدة c. بوب لا يعرف هذه المحادثة. اطلب من خلال 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.
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 السابقة للمحادثة، يمكن فكشف النكشة. ربما نحتاج إلى الذهاب إلى شيء مثل ** ريشيت مزدوج**.
ملاحظة
A lib might exist to implement group conversations.
تحتاج إلى دعم إيكس في OpenDHT
الاستخدام
إضافة الأدوار؟
هناك قضيتين رئيسيتين من استخدام الدردشة الجماعية:
شيء مثل المادة في الشركة، مع القنوات الخاصة، وبعض الأدوار (المدير/المشاهد/البوت/أو ما شابه) أو للتعليم (حيث يكون عدد قليل فقط نشط).
المحادثات الأفقية مثل المحادثة بين الأصدقاء
Jami will be for which one?
فكرة تنفيذ
شهادة لمجموعة تسجل المستخدم مع علم لدور. يمكن أيضًا إضافة أو إلغاء.
انضم إلى المحادثة
فقط عن طريق دعوة مباشرة
عبر رابط/رمز الـ "كيو آر"
عبر اسم الغرفة؟
ما نحتاج إليه
السرية: يجب ألا يتمكن الأعضاء خارج الدردشة الجماعية من قراءة الرسائل في المجموعة
السرية المسبقة: إذا تم تعرض أي مفتاح من المجموعة للخطر، يجب أن تظل الرسائل السابقة سرية (قدر الإمكان)
ترتيب الرسائل: هناك حاجة إلى أن تكون الرسائل في الترتيب الصحيح
التزام المزامنة: هناك أيضا حاجة للتأكد من الحصول على جميع الرسائل في أقرب وقت ممكن.
الإستمرار: في الواقع، تبقى رسالة على DHT لمدة 10 دقائق فقط. لأنه أفضل توقيت يتم حسابه لهذا النوع من DHT. لإستمرار البيانات، يجب على العقدة إعادة وضع القيمة على DHT كل 10 دقائق. طريقة أخرى للقيام بها عندما يكون العقدة خارج الاتصال هي السماح للعقدات إعادة وضع البيانات. ولكن إذا بعد 10 دقائق، ما زال 8 عقدات هنا، فسوف يقومون ب 64 طلبًا (وهو تعريضي). الطريقة الحالية لتجنب التسريب عن البريد الإلكتروني لهذا يتم استفسارها. هذا ما زال سيفعل 64 طلبًا ولكن يحد من زيادة الحد الأقصى إلى 8 عقدات.
الطرق الأخرى الموزعة
احتاج الى بعض التحقيقات
أحتاج إلى بعض التحقيقات
أحتاج إلى بعض التحقيقات
بناء على العمل الحالي لدينا
يمكن أن تستند الدردشة الجماعية إلى نفس العمل الذي لدينا بالفعل للأجهزة المتعددة (ولكن هنا، مع شهادة جماعية). المشاكل التي يجب حلها:
المزامنة التاريخ هذه تحتاج إلى نقل قاعدة البيانات من العميل إلى الديمون
إذا لم يكن هناك أحد متصل، لا يمكن التزام المزامنة، والشخص لن يرى أبدا المحادثة
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)