סרם
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
תעודת המכשיר שלו ב ̀ /מכשירים
ה-CRL שלו ב- ̀ /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:
מוסיף את URI הזמנה ב
/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 לא מגדיר איך לאסור מישהו]
סיגנל, ללא שרת מרכזי לשיחה בקבוצה (EDIT: הם לאחרונה שינו את נקודה זו), לא נותן את היכולת לסגור מישהו מהקבוצה.
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, כל הקבצים של בוב ב /members, /admins, /invited, /CRLs, /devices ניתן להסיר (או רק ב /devices אם זה מכשיר שהוא אסור) ותוכניות בוב ניתן לשים ב /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, /CRLs, ניתן להוסיף מחדש (או רק ב /מכשירים אם זה מכשיר שאינו אסור) ולקבל למכשיר repo
תבטל שיחה
שמור ב- convInfos removed=time::now() (כמו שמורContact save ב- Contacts) שהשיחה נמחקת ומזדיינת עם מכשירים של משתמשים אחרים
אם מקבלים מחויבות חדשה לשיחה זו, זה מתעלם.
אם ג’מי יפתח את הדואר והפסק הדיון עדיין קיים, השיחה לא מפורסמת לקוחות.
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 מתאימה)
ואז, כאשר קשר מקבל את ההצעה, תקופה של סינכרון נחוצה, כי הקשר עכשיו צריך לקלון את השיחה.
removeContact() ימחק את הקשר והשיחות הקשורות 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).
שיחות מבקשות תיאור
בקשות שיחות מופיעות ב Map<String, String> עם המפתחות הבאות:
id: the conversation ID
from: URI of the sender
קיבלתי: סימן זמן
כותרת: (באלץ) שם לשיחה
תיאור: (באלץ)
avatar: (optional) the profile picture
סינכרון פרופיל של שיחה
כדי להיות מזהה, שיחה צריכה בדרך כלל מעטהנתונים, כגון כותרת (למשל: ג’מי), תיאור (למשל: כמה קישורים, מהו הפרויקט, וכו«) ותמונה (לוגו הפרויקט).
אחסון במחסום
הפרופיל של השיחה מאוחסן בקובץ 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)
”איגנורהודעות“ - להתעלם מהודעות של הודעות חדשות בשיחה זו
”סמל“ - להגדיר אימוגי מקובל.
העדפות אלה מאוחסרות בפקט 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
. במקרה זה, ייבחר הקומט עם האש גבוה יותר (למשל 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
תיקון מחדש של חשבון (חבר/יצוא)
האריכיון חייב להכיל שיחהId כדי להיות מסוגל לאחזר שיחות על מחברות חדשות לאחר ייבוא מחדש (כי אין הזמנה בשלב זה). אם מחברת באה לשיחה לא נוכחת יש שתי אפשרויות:
השיחה הייתה שם, במקרה הזה, הדיימון מסוגל לשחזר את השיחה הזאת
ה- conversationId חסר, כך שהדיימון מבקש (דרך הודעה
{{"תطبيق/זמין", 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.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}
) כל הנתונים המגיעים.
כאשר העברה מסיימת או הכניסה נסגרה, 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)
משמש לשלוח הודעות למכשירים ניידים (להפעיל הודעות דחוף) ולהתחיל חיבורים TCP.
פעילות רשת
תהליך להזמין מישהו
אליס רוצה להזמין את בוב:
אליס מוסיפה בוב לשיחה
Alice generates an invite: { ”application/invite+json“ : { ”conversationId“: ”$id“, ”members“: [{…}] }}
שתי אפשרויות לשלוח הודעה a. אם לא מחוברת, באמצעות DHT b. אחרת, אליס שולחת על ערוץ SIP
שתי אפשרויות עבור בוב a. מקבל את ההזמנה, אות משולב עבור הלקוח b. לא מחובר, כך לעולם לא יקבל את ההזמנה כי אליס לא צריכה לדעת אם בוב פשוט התעלם או חסם אליס. הדרך היחידה היא לשחזר הזמנה חדשה באמצעות הודעה חדשה (ראו סצנאר הבא)
תהליך של שלוח הודעה למישהו
אליס רוצה לשלוח הודעה לבוב:
אליס מוסיפה הודעה למכירה, נותנת תעודת זהות
אליס מקבלת הודעה (ממש עצמה) אם מצליחה
שתי אפשרויות, אליס ובוב מחוברות או לא. בשתי המקרים מסר מתבצע: { ”תחילות/ימ-גיטמעסג-איד“ : ”{”איד“:“\(קונוויד", "תחייב":"\)קומטאיד“, ”מכשיראיד“: ”$אליס_מכשיר_חש“}“}. א. אם לא מחוברים, באמצעות DHT b. אחרת, אליס שולחת על ערוץ SIP
ארבעה אפשרויות עבור בוב: א. בוב לא מחובר אליס, אז אם הוא בוטח באליס, בקש קשר חדש ולך ל- b. אם הוא מחובר, קח אליס ולהודיע על הודעות חדשות. בוב לא יודע את השיחה הזאת. בקש דרך DHT לקבל הזמנה קודם כדי להיות מסוגל לקבל את השיחה הזאת ({”הבקשה/זמנה“, שיחהId}) ד. בוב מחובר (אין רשת, או פשוט סגור). הוא לא יקבל את הודעה החדשה אבל ינסה להתקשר כאשר השיחה הבאה תתרחש
יישום
[השידור: שיעורי שיחה של שוואר]
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.
זקוקה לתמיכה ב-ECC ב- OpenDHT
שימוש
להוסיף תפקידים?
יש שתי תיבות שימוש מרכזיות בשיחות קבוצתיות:
משהו כמו Mattermost בחברה, עם ערוצים פרטיים, ומחלקים מסוימים של תפקידים (admin/spectator/bot/etc) או עבור חינוך (כאן רק כמה פעילים).
שיחות אופיות כמו שיחה בין חברים.
Jami will be for which one?
רעיון ליישום
תעודת עבור קבוצה שהחתום משתמש עם דגל עבור תפקיד. ניתן גם להוסיף או לבטל.
הצטרף לשיחה
רק באמצעות הזמנה ישירה
באמצעות קישור/קוד קיר/כל מה
דרך שם חדר?
מה שאנחנו צריכים
סודיות: חברי מחוץ לשיחה הקבוצתית לא צריכים להיות מסוגלים לקרוא הודעות בקבוצת
סודיות מקדימה: אם כל מפתח מהקבוצת נפגע, הודעות קודמות צריכות להישאר סודיות (כל עוד זה אפשרי)
סדר הודעות: יש צורך להיות הודעות בסדר הנכון
סינכרון: יש גם צורך לוודא שיש לך את כל ההודעות בהקדם האפשרי.
עמידות: למעשה, הודעה על DHT חי רק 10 דקות. כי זה הזמן הטוב ביותר שחושב עבור סוג זה של DHT. כדי לעמיד נתונים, הערך חייב להוסיף את הערך על DHT כל 10 דקות. דרך אחרת לעשות כאשר הערך הוא מקולקול היא לתת הערכים להוסיף את הנתונים. אבל, אם אחרי 10 דקות, 8 הערכים עדיין כאן, הם יעשו 64 בקשות (והזה הוא אקופוננציאלי). הדרך הנוכחית למנוע ספאם עבור זה הוא נשאל. זה עדיין יעשה 64 בקשות אבל להגביל את העומס הגבוה ל 8 הערכים.
דרכים מከፋፈלות אחרות
IPFS: צריך קצת חקירה
אני צריך קצת חקירה.
אני צריך קצת חקירה.
בהתבסס על העבודה הנוכחית שיש לנו
שיחת קבוצה יכולה להתבסס על אותה עבודה שיש לנו כבר עבור מכשירים רבים (אבל כאן, עם תעודת קבוצה). בעיות לפתור:
זה צריך להעביר את הנתונים מהלקוח אל הדיימון.
אם אף אחד לא מחובר, ההזכוז לא יכול להיעשות, והאדם לעולם לא יראה את השיחה
עוד 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)