mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-02-10 17:03:12 +00:00
chore: shared memory db with name
This commit is contained in:
parent
4f6705603d
commit
75fd6acda9
@ -1,26 +1,19 @@
|
|||||||
//! Example: Ping-Pong Chat
|
//! Example: Ping-Pong Chat
|
||||||
//!
|
//!
|
||||||
//! This example demonstrates a back-and-forth conversation between two users
|
//! This example demonstrates a back-and-forth conversation between two users
|
||||||
//! using temporary file storage.
|
//! using in-memory storage.
|
||||||
//!
|
//!
|
||||||
//! Run with: cargo run -p logos-chat --example ping_pong
|
//! Run with: cargo run -p logos-chat --example ping_pong
|
||||||
|
|
||||||
use logos_chat::{ChatManager, StorageConfig};
|
use logos_chat::ChatManager;
|
||||||
use tempfile::tempdir;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("=== Ping-Pong Chat Example ===\n");
|
println!("=== Ping-Pong Chat Example ===\n");
|
||||||
|
|
||||||
// Create temporary directories for storage
|
// Create two chat participants with in-memory storage
|
||||||
let dir = tempdir().expect("Failed to create temp dir");
|
// Each ChatManager has its own shared in-memory SQLite database
|
||||||
let alice_db = dir.path().join("alice.db");
|
let mut alice = ChatManager::in_memory("alice").expect("Failed to create Alice's chat manager");
|
||||||
let bob_db = dir.path().join("bob.db");
|
let mut bob = ChatManager::in_memory("bob").expect("Failed to create Bob's chat manager");
|
||||||
|
|
||||||
// Create two chat participants with file-based storage
|
|
||||||
let mut alice = ChatManager::open(StorageConfig::File(alice_db.to_str().unwrap().to_string()))
|
|
||||||
.expect("Failed to create Alice's chat manager");
|
|
||||||
let mut bob = ChatManager::open(StorageConfig::File(bob_db.to_str().unwrap().to_string()))
|
|
||||||
.expect("Failed to create Bob's chat manager");
|
|
||||||
|
|
||||||
println!("Created participants:");
|
println!("Created participants:");
|
||||||
println!(" Alice: {}", alice.local_address());
|
println!(" Alice: {}", alice.local_address());
|
||||||
|
|||||||
@ -39,6 +39,7 @@ pub enum ChatManagerError {
|
|||||||
///
|
///
|
||||||
/// It manages identity, inbox, and chats with all state persisted to SQLite.
|
/// It manages identity, inbox, and chats with all state persisted to SQLite.
|
||||||
/// Chats are loaded from storage on each operation - no in-memory caching.
|
/// Chats are loaded from storage on each operation - no in-memory caching.
|
||||||
|
/// Uses a single shared database for both chat metadata and ratchet state.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
@ -68,6 +69,8 @@ pub struct ChatManager {
|
|||||||
/// Storage for chat metadata (identity, inbox keys, chat records).
|
/// Storage for chat metadata (identity, inbox keys, chat records).
|
||||||
storage: ChatStorage,
|
storage: ChatStorage,
|
||||||
/// Storage config for creating ratchet storage instances.
|
/// Storage config for creating ratchet storage instances.
|
||||||
|
/// For file/encrypted databases, SQLite handles connection efficiently.
|
||||||
|
/// For in-memory testing, use SharedInMemory to share data.
|
||||||
storage_config: StorageConfig,
|
storage_config: StorageConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,8 +106,14 @@ impl ChatManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new in-memory ChatManager (for testing).
|
/// Creates a new in-memory ChatManager (for testing).
|
||||||
pub fn in_memory() -> Result<Self, ChatManagerError> {
|
///
|
||||||
Self::open(StorageConfig::InMemory)
|
/// Uses a shared in-memory SQLite database so that multiple storage
|
||||||
|
/// instances within the same ChatManager share data.
|
||||||
|
///
|
||||||
|
/// The `db_name` should be unique per ChatManager instance to avoid
|
||||||
|
/// sharing data between different users.
|
||||||
|
pub fn in_memory(db_name: &str) -> Result<Self, ChatManagerError> {
|
||||||
|
Self::open(StorageConfig::SharedInMemory(db_name.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new RatchetStorage instance using the stored config.
|
/// Creates a new RatchetStorage instance using the stored config.
|
||||||
@ -334,13 +343,13 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_chat_manager() {
|
fn test_create_chat_manager() {
|
||||||
let manager = ChatManager::in_memory().unwrap();
|
let manager = ChatManager::in_memory("test1").unwrap();
|
||||||
assert!(!manager.local_address().is_empty());
|
assert!(!manager.local_address().is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_identity_persistence() {
|
fn test_identity_persistence() {
|
||||||
let manager = ChatManager::in_memory().unwrap();
|
let manager = ChatManager::in_memory("test2").unwrap();
|
||||||
let address = manager.local_address();
|
let address = manager.local_address();
|
||||||
|
|
||||||
// Identity should be persisted
|
// Identity should be persisted
|
||||||
@ -351,15 +360,15 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_intro_bundle() {
|
fn test_create_intro_bundle() {
|
||||||
let mut manager = ChatManager::in_memory().unwrap();
|
let mut manager = ChatManager::in_memory("test3").unwrap();
|
||||||
let bundle = manager.create_intro_bundle();
|
let bundle = manager.create_intro_bundle();
|
||||||
assert!(bundle.is_ok());
|
assert!(bundle.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_start_private_chat() {
|
fn test_start_private_chat() {
|
||||||
let mut alice = ChatManager::in_memory().unwrap();
|
let mut alice = ChatManager::in_memory("alice1").unwrap();
|
||||||
let mut bob = ChatManager::in_memory().unwrap();
|
let mut bob = ChatManager::in_memory("bob1").unwrap();
|
||||||
|
|
||||||
// Bob creates an intro bundle
|
// Bob creates an intro bundle
|
||||||
let bob_intro = bob.create_intro_bundle().unwrap();
|
let bob_intro = bob.create_intro_bundle().unwrap();
|
||||||
@ -379,7 +388,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_inbox_key_persistence() {
|
fn test_inbox_key_persistence() {
|
||||||
let mut manager = ChatManager::in_memory().unwrap();
|
let mut manager = ChatManager::in_memory("test4").unwrap();
|
||||||
|
|
||||||
// Create intro bundle (should persist ephemeral key)
|
// Create intro bundle (should persist ephemeral key)
|
||||||
let intro = manager.create_intro_bundle().unwrap();
|
let intro = manager.create_intro_bundle().unwrap();
|
||||||
@ -392,8 +401,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_chat_exists() {
|
fn test_chat_exists() {
|
||||||
let mut alice = ChatManager::in_memory().unwrap();
|
let mut alice = ChatManager::in_memory("alice2").unwrap();
|
||||||
let mut bob = ChatManager::in_memory().unwrap();
|
let mut bob = ChatManager::in_memory("bob2").unwrap();
|
||||||
|
|
||||||
let bob_intro = bob.create_intro_bundle().unwrap();
|
let bob_intro = bob.create_intro_bundle().unwrap();
|
||||||
let (chat_id, _) = alice.start_private_chat(&bob_intro, "Hello!").unwrap();
|
let (chat_id, _) = alice.start_private_chat(&bob_intro, "Hello!").unwrap();
|
||||||
@ -405,8 +414,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_chat() {
|
fn test_delete_chat() {
|
||||||
let mut alice = ChatManager::in_memory().unwrap();
|
let mut alice = ChatManager::in_memory("alice3").unwrap();
|
||||||
let mut bob = ChatManager::in_memory().unwrap();
|
let mut bob = ChatManager::in_memory("bob3").unwrap();
|
||||||
|
|
||||||
let bob_intro = bob.create_intro_bundle().unwrap();
|
let bob_intro = bob.create_intro_bundle().unwrap();
|
||||||
let (chat_id, _) = alice.start_private_chat(&bob_intro, "Hello!").unwrap();
|
let (chat_id, _) = alice.start_private_chat(&bob_intro, "Hello!").unwrap();
|
||||||
@ -427,7 +436,7 @@ mod tests {
|
|||||||
let dir = tempdir().unwrap();
|
let dir = tempdir().unwrap();
|
||||||
let db_path = dir.path().join("test.db");
|
let db_path = dir.path().join("test.db");
|
||||||
|
|
||||||
let mut bob = ChatManager::in_memory().unwrap();
|
let mut bob = ChatManager::in_memory("bob4").unwrap();
|
||||||
let bob_intro = bob.create_intro_bundle().unwrap();
|
let bob_intro = bob.create_intro_bundle().unwrap();
|
||||||
|
|
||||||
let chat_id;
|
let chat_id;
|
||||||
|
|||||||
@ -8,8 +8,11 @@ use crate::StorageError;
|
|||||||
/// Configuration for SQLite storage.
|
/// Configuration for SQLite storage.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum StorageConfig {
|
pub enum StorageConfig {
|
||||||
/// In-memory database (for testing).
|
/// In-memory database (isolated, for simple testing).
|
||||||
InMemory,
|
InMemory,
|
||||||
|
/// Shared in-memory database with a name (multiple connections share data).
|
||||||
|
/// Use this when you need multiple storage instances to share the same in-memory DB.
|
||||||
|
SharedInMemory(String),
|
||||||
/// File-based SQLite database.
|
/// File-based SQLite database.
|
||||||
File(String),
|
File(String),
|
||||||
/// SQLCipher encrypted database.
|
/// SQLCipher encrypted database.
|
||||||
@ -29,6 +32,17 @@ impl SqliteDb {
|
|||||||
pub fn new(config: StorageConfig) -> Result<Self, StorageError> {
|
pub fn new(config: StorageConfig) -> Result<Self, StorageError> {
|
||||||
let conn = match config {
|
let conn = match config {
|
||||||
StorageConfig::InMemory => Connection::open_in_memory()?,
|
StorageConfig::InMemory => Connection::open_in_memory()?,
|
||||||
|
StorageConfig::SharedInMemory(ref name) => {
|
||||||
|
// Use URI mode to create a shared in-memory database
|
||||||
|
// Multiple connections with the same name share the same data
|
||||||
|
let uri = format!("file:{}?mode=memory&cache=shared", name);
|
||||||
|
Connection::open_with_flags(
|
||||||
|
&uri,
|
||||||
|
rusqlite::OpenFlags::SQLITE_OPEN_URI
|
||||||
|
| rusqlite::OpenFlags::SQLITE_OPEN_READ_WRITE
|
||||||
|
| rusqlite::OpenFlags::SQLITE_OPEN_CREATE,
|
||||||
|
)?
|
||||||
|
}
|
||||||
StorageConfig::File(ref path) => Connection::open(path)?,
|
StorageConfig::File(ref path) => Connection::open(path)?,
|
||||||
StorageConfig::Encrypted { ref path, ref key } => {
|
StorageConfig::Encrypted { ref path, ref key } => {
|
||||||
let conn = Connection::open(path)?;
|
let conn = Connection::open(path)?;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user