# node-to-node file share ###### tags: `Kizuna-architecture` <style> .ui-infobar, #doc.markdown-body { max-width: 2000px; } </style> ## User Stories - [As a user, I want to send files to a chat so that I can share my files.](https://beyonder.atlassian.net/browse/KIZUNA-63) - [As a user, I want to send media files to a chat so that I can share my images/videos.](https://beyonder.atlassian.net/browse/KIZUNA-64) - [As a user, I want to send voice notes to a chat/groupchat so that I can share that voice note](https://beyonder.atlassian.net/browse/KIZUNA-65) - [I want to be notified of incoming file attachment message so I know that someone sent me a file](https://beyonder.atlassian.net/browse/KIZUNA-371) - [I want to see media files sent to the chat so that I can check what they sent.](https://beyonder.atlassian.net/browse/KIZUNA-61) - [I want to see shared files/media in a chat/group chat so that I can browse through previously sent files.](https://beyonder.atlassian.net/browse/KIZUNA-96) - [I want to download files sent to the chat so that I can have it locally.](https://beyonder.atlassian.net/browse/KIZUNA-60) - [I want to choose whether to auto download files/media ](https://beyonder.atlassian.net/browse/KIZUNA-331)(maybe move to preference?) - [I want to choose whether to have preview of files/media](https://beyonder.atlassian.net/browse/KIZUNA-332)(maybe move to preference?) ## Notes * 16Mb file size limit * will become similar to P2PMessage * chunking and DHT storage can be done for group file sending ## Entry Relationship Diagram ```mermaid graph LR subgraph p2pmessage zome subgraph agents alice bobby end subgraph file chunks in DHT file_chunk_1 file_chunk_2 file_chunk_n end subgraph file metadata in source chains file_metadata_1 alice.->|has in source chain|file_metadata_1 bobby.->|has in source chain|file_metadata_1 file_metadata_1.->file_chunk_1 file_metadata_1.->file_chunk_2 file_metadata_1.->file_chunk_n end end ``` ## File Sharing (Using external chunking) ### Comments and Questions * Is it safe storing chunks of files in DHT? * prolly not * maybe if we do encryption on chunks * For synchronous comms, do we do encyrption or is it redundant because of QUIC? How about on Holo? is local device to HoloPort encrypted also? * Is looping through chunks in the UI and calling a zome function per chunk efficient? * What is the size limit per call to a zome function from the UI? * May provide an advantage in error recovery midway through uploads * TODO: Asynchronous file sending * Would be better if we can just send the chunks through call_remote * No ecnryption design yet * Guillem: seems prone to attacks; can we commit entry in DHT and just and send the link ### Entry Structure ```rust= #[hdk_entry(id="file_metadata", visibility="private")] struct FileMetadata { author: AgentPubKey, receiver: AgentPubKey, file_name: String, file_size: usize, file_type: String, time_sent: Timestamp, time_received: Option<Timestamp>, chunks: Vec<EntryHash> // addresses of each chunk in the DHT } #[hdk_entry(id="file_chunk", visibility="public")] struct FileChunk(Vec<u8>); pub struct FileMetadataOutput { author: AgentPubKey, receiver: AgentPubKey, file_name: String, file_size: usize, file_type: String, time_sent: Timestamp, time_received: Option<Timestamp>, chunks: Vec<EntryHash> } pub struct FileInput { pub receiver: AgentPubKey, pub file_name: String, pub file_size: usize, pub file_type: String, pub chunks: Vec<EntryHash>, pub hash: String } ``` ```mermaid sequenceDiagram participant AUI as Alice_UI participant ACD as Alice_Conversation_Cell AUI-->>AUI: chunk file AUI-->>AUI: construct empty metadata struct loop for all file chunks rect rgba(0,255,0,0.5) AUI-->>ACD: call `upload_chunk` ACD-->>AUI: return chunk address in DHT end AUI-->>AUI: add chunk address to metadata end AUI-->>AUI: generate hash of entire file AUI-->>AUI: add file hash to metadata rect rgba(0,255,0,0.5) AUI-->>ACD: call `send_file` ACD-->>AUI: return FileMetadata end ``` ## Zome functions ### upload_chunk ```rust= // Function to commit a chunk of a file into the DHT. // Called iteratively in the front-end over the chunks of a file. pub(crate) fn upload_chunk( file_chunk_input: FileChunk ) -> ExternResult<EntryHash> ``` ```mermaid sequenceDiagram participant AUI as Alice_UI participant ACD as Alice_Conversation_Cell participant DHT as DHT ACD-->>ACD: construct FileChunk entry ACD-->>DHT: commit entry to DHT DHT-->>ACD: return address ACD-->>AUI: return address of FileChunk in DHT ``` ### send_file ```rust= // Function to send the file metadata synchronously from one agent to another. pub(crate) fn send_file( file_input: FileInput ) -> ExternResult<FileMetadataOption> ``` ```mermaid sequenceDiagram participant AUI as Alice_UI participant ACD as Alice_Conversation_Cell participant BCD as Bobby_Conversation_Cell participant DHT as DHT loop for all chunk addresses rect rgba(0,0,255,0.3) ACD-->>DHT: call `get_bytes_from_chunks` end DHT-->>ACD: return file bytes end ACD-->>ACD: compute file hash from bytes alt computed file hash != input file hash ACD-->>AUI: return error "file integrity check failed" else computed file hash = input file hash rect rgba(0,255,0,0.5) ACD-->>BCD: call_remote `receive_file_metadata` BCD-->>ACD: return call_remote result end alt call_remote ok ACD-->>ACD: construct FileMetadata entry ACD-->>ACD: commit FileMetadata entry to source chain else call_remote timeout Note over ACD: TODO: async case else call_remote unauthorized ACD-->>AUI: return error "No proper authorization" end end ``` ### get_bytes_from_chunks ```rust= // internal helper function pub fn get_bytes_from_chunks( chunks_hashes: Vec<EntryHash> ) -> ExternResult<Vec<u8>> ``` ```mermaid sequenceDiagram participant ACD as Alice_Conversation_Cell participant DHT as DHT loop for all chunk addresses rect rgba(0,0,255,0.3) ACD-->>DHT: call `get_file_chunk` end DHT-->>ACD: return file chunk bytes end ACD-->>ACD: assemble file from bytes ACD-->>ACD: return file_bytes ``` ### get_file_chunk ```rust= // internal helper function pub fn get_file_chunk( file_chunk_hash: FileChunk ) -> ExternResult<EntryHash> ``` ```mermaid sequenceDiagram participant ACD as Alice_Conversation_Cell participant DHT as DHT ACD-->>DHT: get entry of file chunk in DHT DHT-->>ACD: return entry ``` ### receive_file_metadata ```rust= pub(crate) fn receive_file_metadata( metadata_input: FileMetadataOutput ) -> ExternResult<FileMetadataOption> ``` ```mermaid sequenceDiagram participant ACD as Alice_Conversation_Cell participant BCD as Bobby_Conversation_Cell BCD-->>BCD: construct FileMetdataEntry BCD-->>BCD: generate and add timestamp to time_received field of FileMetadataEntry BCD-->>BCD: commit entry to source chain BCD-->>BCD: construct FileMetadataOutput from entry BCD-->>BUI: emit signal "file has been received" BCD-->>ACD: return FileMetadataOutput ``` ## Validation ### Entries ### Links