# Refactored P2P Messaging ###### tags: `Kizuna-architecture` <style> .ui-infobar, #doc.markdown-body { max-width: 1000px; } </style> <img src="https://i.imgur.com/fVyoNsV.png" width="150" style="padding-right:5px"/> <img src="https://i.imgur.com/ht3KLk4.png" width="150"/> #### Reply <img src="https://i.imgur.com/qX84J6o.png" width="150" style="padding:5px"/> <img src="https://i.imgur.com/WnfFxXX.png" width="150" style="padding:5px"/> <img src="https://i.imgur.com/j8LOqxO.png" width="150" style="padding:5px"/> ## Entries ### Message ```rust= #[hdk_entry(id = "p2pmessage", visibility = "private")] pub struct P2PMessage { author: AgentPubKey, receiver: AgentPubKey, payload: Payload, time_sent: Timestamp, reply_to: Option<EntryHash> } ``` ### Receipt ```rust= #[hdk_entry(id = "p2pmessagereceipt", visibility = "private")] pub struct P2PMessageReceipt { id: Vec<EntryHash>, time_received: Option<Timestamp>, status: Status } ``` ### Pin ```rust= #[hdk_entry(id = "p2pmessagereceipt", visibility = "private")] pub struct P2PMessagePin { id: Vec<EntryHash>, conversants: Vec<AgentPubKey> status: PinStatus } ``` ### File Bytes ```rust= #[hdk_entry(id = "p2pfilebytes", visibility = "private")] pub struct P2PFileBytes (SerializedBytes) ``` ## Entry Relationship Diagram ```mermaid graph LR subgraph p2pmessage zome subgraph agents alice bobby end subgraph messages message_1 receipt_1 message_2 receipt_2 alice.->|has in source chain|message_1 bobby.->|has in source chain|message_1 alice.->|has in source chain|message_2 bobby.->|has in source chain|message_2 alice.->|has in source chain|receipt_1 bobby.->|has in source chain|receipt_1 alice.->|has in source chain|receipt_2 bobby.->|has in source chain|receipt_2 receipt_1.->message_1 receipt_2.->message_2 end subgraph async messages in DHT async_1 bobby-->|async_messages|async_1 message_2 ==> async_1 end end ``` ## Data Structures ### Message Receipt Status ```rust= enum Status { Sent, Received {timestamp: Timestamp}, Read {timestamp: Timestamp} } ``` ### PinStatus ```rust= pub struct PinStatus { pinned: { timestamp: Timestamp }, unpinnned: { timestamp: Timestamp } } ``` ### File Metadata ```rust= struct FileMetadata { file_name: String, file_size: usize, file_type: String, file_hash: EntryHash // entryhash of File??? } ``` ### File Type ```rust= enum FileType { Image { thumbnail: serializedBytes }, Video { thumbnail: SerializedBytes }, Others } ``` ### Payload ```rust= enum Payload { Text {payload: String}, File { metadata: FileMetadata, file_type: FileType } } ``` <!-- Input Structures --> ### Message Input ```rust= struct MessageInput { receiver: AgentPubKey, payload: PayloadInput, file_bytes: Option<SerializedBytes>, reply_to: Option<EntryHash> } ``` ### Read Receipt Input ```rust= struct ReadReceiptInput { sender: AgentPubKey, receipt: P2PMessageReceipt, } ``` ### File Metadata Input ```rust= /* This will be defined in a /commons crate that will be used for both p2pmessage and group zome */ struct FileMetadataInput { file_name: String, file_size: usize, file_type: String, } ``` ### Payload Input ```rust= struct PayloadInput { Text {payload: String}, File { metadata: FileMetadataInput file_type: FileType } } ``` ### PinInput ```rust= pub struct PinMessageInput { id: Vec<EntryHash>, conversants: Vec<AgentPubkey>, status: PinStatus, } ``` <!-- Output Structures --> ### Messaage Output ```rust= pub struct P2PMessagesOutput( AgentMessages, MessageContents, ReceiptContents ) ``` ### Agent - Message Hash Map ```rust= pub struct AgentMessages(HashMap<AgentPubKey, Vec<Entryhash>>) ``` ### Message Hash - Message Hash Map ```rust= pub struct MessageContents(HashMap<EntryHash, MessageBundle>) ``` ### Receipt Hash - Receipt Hash Map ```rust= pub struct ReceiptContents(HashMap<EntryHash, P2PMessageReceipt>) ``` ### Message Bundle ```rust= pub struct MessageBundle(P2PMessageElement, Vec<ReceiptHash>) ``` ### PinContents ```rust= pub struct PinMessageOutput(HashMap<String, P2PMessagePin>) ``` ## Zome Functions ### `init` ```mermaid sequenceDiagram participant ACC as Alice_Conversation_Cell participant BCC as Bobby_Conversation_Cell par alice init ACC-->>ACC: set unrestricted access to receive_message ACC-->>ACC: set unrestricted access to notify_delivery ACC-->>ACC: set unrestricted access to recv_remote_signal and bob init BCC-->>BCC: set unrestricted access to receive_message BCC-->>BCC: set unrestricted acesss to notify_delivery BCC-->>BCC: set unrestricted access to recv_remote_signal end ``` ### `send_message` ```rust= fn send_message(message_input: MessageInput) -> ExternResult<MessageBundle> struct MessageInput { receiver: AgentPubKey, payload: PayloadInput, file_bytes: Option<SerializedBytes>, reply_to: Option<EntryHash> } struct MessageBundle(P2PMessageElement, Vec<P2PMessageReceiptElement>) ``` ```mermaid sequenceDiagram participant AUI as Alice_UI participant ACC as Alice_Conversation_Cell participant BCC as Bobby_Conversation_Cell participant BUI as Bobby_UI participant NH as Neighborhood AUI-->>ACC: call `send_message` function rect rgba(255,0,0,0.3) ACC-->>ACC: check if receiver is blocked by calling `in_blocked` <br> in Contacts zome end opt receiver is blocked ACC-->>AUI: return error (cannot send to blocked) end opt payload is File ACC-->>ACC: construct P2PFileBytes ACC-->>ACC: commit P2PFileBytes end ACC-->>ACC: construct P2PMessage from input ACC-->>ACC: construct 'Sent' P2PMesageReceipt ACC-->>ACC: commit P2PMessage and P2PMessageReceipt to source chain <br> while calling post_commit callback ACC-->>AUI: return MessageBundle <br> (skip this until post_commit becomes available) Note over ACC: yellow box will be moved to post commit rect rgba(255,255,0,0.2) ACC-->>BCC: call_remote Bobby's `receive_message` function alt call_remote ok (receiver is online) rect rgba(0, 0, 255, 0.4) BCC-->>BCC: invoke `receive_message` end BCC-->>ACC: return P2PMessage and P2PMessageReceipt opt payload is File ACC-->>ACC: commit P2PFileBytes end ACC-->>ACC: commit P2PMessageReceipt to source chain ACC-->>AUI: return MessageBundle else call_remote timeout (receiver is offline) Note over ACC, BCC: timeout can also mean that the peer was not found in which case the receiver needs to poll the message from the neighborhood rect rgba(0,255,0,0.8) ACC-->>NH: call `send_to_neighbor` with P2PMessage as payload end ACC-->>ACC: commit P2PMessageReceipt to source chain ACC-->>AUI: return MessageBundle else call_remote unauthorized Note over ACC, BCC: case should not exist end end ```