---
# System prepended metadata

title: Refactored P2P Messaging
tags: [Kizuna-architecture]

---

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

