use futures_channel::oneshot;
use smol::{channel, lock::Mutex, stream::StreamExt as _};
use smoldot::database::full_sqlite::SqliteFullDatabase;
use std::{pin::pin, thread};
pub use smoldot::database::full_sqlite::StorageAccessError;
pub struct DatabaseThread {
sender: Mutex<channel::Sender<Exec>>,
}
type Exec = Box<dyn FnOnce(&SqliteFullDatabase) + Send>;
impl DatabaseThread {
pub async fn with_database<T: Send + 'static>(
&self,
closure: impl FnOnce(&SqliteFullDatabase) -> T + Send + 'static,
) -> T {
let (tx, rx) = oneshot::channel();
self.sender
.lock()
.await
.send(Box::new(move |db| {
let _ = tx.send(closure(db));
}))
.await
.unwrap();
rx.await.unwrap()
}
pub async fn with_database_detached(
&self,
closure: impl FnOnce(&SqliteFullDatabase) + Send + 'static,
) {
self.sender
.lock()
.await
.send(Box::new(move |db| {
closure(db);
}))
.await
.unwrap();
}
}
impl From<SqliteFullDatabase> for DatabaseThread {
fn from(db: SqliteFullDatabase) -> DatabaseThread {
let (sender, rx) = channel::bounded::<Box<dyn FnOnce(&SqliteFullDatabase) + Send>>(256);
thread::Builder::new()
.name("sqlite-database".into())
.spawn(move || {
let mut rx = pin!(rx);
while let Some(closure) = smol::block_on(rx.next()) {
closure(&db)
}
})
.unwrap();
DatabaseThread {
sender: Mutex::new(sender),
}
}
}