feat: delete a chat

This commit is contained in:
kaichaosun 2026-02-06 00:31:36 +08:00
parent 537d48d5fd
commit 3e4e57ec6c
No known key found for this signature in database
GPG Key ID: 223E0F992F4F03BF
2 changed files with 61 additions and 5 deletions

View File

@ -6,7 +6,8 @@ A terminal chat application built with [ratatui](https://ratatui.rs/) using the
- 💬 End-to-end encrypted messaging using the Double Ratchet algorithm
- 📁 File-based transport for local simulation (no network required)
- 💾 Persistent storage (SQLite)
- 💾 Persistent storage (SQLite + JSON state)
- 🔄 Multiple chat support with chat switching
- 🖥️ Beautiful terminal UI with ratatui
## Usage
@ -40,11 +41,19 @@ cargo run -p chat-cli -- bob
| `/help` | Show available commands |
| `/intro` | Generate and display your introduction bundle |
| `/connect <user> <bundle>` | Connect to a user using their introduction bundle |
| `/peers` | List available peers |
| `/chats` | List all your established chats |
| `/switch <user>` | Switch to a different chat |
| `/delete <user>` | Delete a chat (removes session and crypto state) |
| `/peers` | List transport-level peers (users with inbox directories) |
| `/status` | Show connection status and your address |
| `/clear` | Clear message history |
| `/clear` | Clear current chat's message history |
| `/quit` or `Esc` or `Ctrl+C` | Exit the application |
#### `/peers` vs `/chats`
- **`/peers`**: Shows users whose CLI has been started (have inbox directories). These are potential contacts you *could* message.
- **`/chats`**: Shows users you have an **encrypted session** with (via `/connect`). These are active conversations.
### Sending Messages
Simply type your message and press Enter. Messages are automatically encrypted and delivered via file-based transport.
@ -62,8 +71,13 @@ Messages are passed between users via files in a shared directory:
### Storage
User data (identity keys, chat state) is stored in SQLite databases at:
- `chat-cli-data/<username>.db`
Data is stored in the `chat-cli-data/` directory:
| File | Purpose |
|------|---------|
| `<username>.db` | SQLite database for identity keys, inbox keys, chat metadata, and Double Ratchet state |
| `<username>_state.json` | CLI state: username↔chat mappings, message history, active chat |
| `transport/<username>/` | Inbox directory for receiving messages |
### Encryption
@ -88,6 +102,13 @@ $ cargo run -p chat-cli -- bob
# Connected! Bob sends "Hello!" automatically
# Now type messages in either terminal to chat!
# To see your chats:
/chats
# Output: alice (active)
# To switch between chats (if you have multiple):
/switch alice
```
## Architecture

View File

@ -206,6 +206,32 @@ impl ChatApp {
}
}
/// Delete a chat session.
pub fn delete_chat(&mut self, remote_user: &str) -> Result<()> {
if let Some(session) = self.state.sessions.remove(remote_user) {
// Also delete from the library's storage
if let Err(e) = self.manager.delete_chat(&session.chat_id) {
// Log but don't fail - the CLI state is already updated
self.status = format!("Warning: failed to delete crypto state: {}", e);
}
// If we deleted the active chat, clear it
if self.state.active_chat.as_deref() == Some(remote_user) {
// Switch to another chat if available, otherwise clear
self.state.active_chat = self.state.sessions.keys().next().cloned();
}
self.save_state()?;
self.status = format!("Deleted chat with {}", remote_user);
Ok(())
} else {
Err(anyhow::anyhow!(
"No chat with {}. Use /chats to list available chats.",
remote_user
))
}
}
/// Send a message in the current chat.
pub fn send_message(&mut self, content: &str) -> Result<()> {
let active = self
@ -324,6 +350,8 @@ impl ChatApp {
self.add_system_message("/connect <user> <bundle> - Connect to a user");
self.add_system_message("/chats - List all chats");
self.add_system_message("/switch <user> - Switch to chat with user");
self.add_system_message("/delete <user> - Delete chat with user");
self.add_system_message("/peers - List transport peers");
self.add_system_message("/status - Show connection status");
self.add_system_message("/clear - Clear current chat messages");
self.add_system_message("/quit or Esc or Ctrl+C - Exit");
@ -370,6 +398,13 @@ impl ChatApp {
self.switch_chat(args)?;
Ok(Some(format!("Switched to {}", args)))
}
"/delete" => {
if args.is_empty() {
return Ok(Some("Usage: /delete <username>".to_string()));
}
self.delete_chat(args)?;
Ok(Some(format!("Deleted chat with {}", args)))
}
"/peers" => {
let peers = self.transport.list_peers();
if peers.is_empty() {