use crate::Result;
use std::{borrow::Cow, sync::Arc};
use tokio::{
sync::Mutex,
time::{sleep, Duration},
};
use zeroize::Zeroize;
#[derive(Clone)]
pub struct Clipboard {
clipboard: Arc<Mutex<arboard::Clipboard>>,
timeout_seconds: u16,
}
impl Clipboard {
pub fn new() -> Result<Self> {
Self::new_timeout(90)
}
pub fn new_timeout(timeout_seconds: u16) -> Result<Self> {
Ok(Self {
clipboard: Arc::new(Mutex::new(arboard::Clipboard::new()?)),
timeout_seconds,
})
}
pub async fn get_text(&self) -> Result<String> {
let mut clipboard = self.clipboard.lock().await;
Ok(clipboard.get_text()?)
}
pub async fn set_text<'a, T: Into<Cow<'a, str>>>(
&self,
text: T,
) -> Result<()> {
let mut clipboard = self.clipboard.lock().await;
Ok(clipboard.set_text(text)?)
}
pub async fn clear(&self) -> Result<()> {
let mut clipboard = self.clipboard.lock().await;
Ok(clipboard.clear()?)
}
pub async fn set_text_timeout<'a, T: Into<Cow<'a, str>>>(
&self,
text: T,
) -> Result<()> {
let text: Cow<'a, str> = text.into();
let seconds = self.timeout_seconds;
let source_text: Arc<Mutex<String>> =
Arc::new(Mutex::new(text.clone().into_owned()));
self.set_text(text).await?;
tokio::task::spawn(async move {
sleep(Duration::from_secs(seconds.into())).await;
match arboard::Clipboard::new() {
Ok(mut clipboard) => match clipboard.get_text() {
Ok(text) => {
let mut reader = source_text.lock().await;
if *reader == text {
let source = &mut *reader;
source.zeroize();
match clipboard.clear() {
Ok(_) => {
tracing::info!(
timeout = seconds,
"clipboard::clear"
);
}
Err(e) => {
tracing::warn!(
error = ?e,
"clipboard::clear",
)
}
}
}
}
Err(e) => {
tracing::warn!(error = ?e, "clipboard::get_text")
}
},
Err(e) => {
tracing::warn!(error = ?e, "clipboard::new")
}
}
});
Ok(())
}
}