# 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
```