use std::path::PathBuf;
use std::sync::Arc;
use anyhow::Result;
use tokio::sync::{mpsc, watch, Mutex};
use tokio::{task, time};
use tracing::{error, info};
use nikau::logging;
use nikau::x11clipboard::{
reader::{ClipboardReader, ClipboardTypeWatcher},
writer::ClipboardWriter,
ClipboardData,
};
#[tokio::main]
async fn main() -> Result<()> {
logging::init_logging();
let (clipboard_types_tx, mut clipboard_types_rx) = watch::channel(vec![]);
ClipboardTypeWatcher::start(clipboard_types_tx).await?;
let mut reader = ClipboardReader::new().await?;
let type_ = "UTF8_STRING";
let types = vec![
"text/plain",
"text/plain;charset=utf-8",
"STRING",
"TEXT",
"COMPOUND_TEXT",
type_,
];
let (fetch_tx, mut fetch_rx) = mpsc::channel(32);
let max_uncompressed_bytes = 1024 * 1024;
let writer = Arc::new(Mutex::new(
ClipboardWriter::start(
PathBuf::from("/tmp/nikau"),
max_uncompressed_bytes,
fetch_tx,
)
.await?,
));
task::spawn(async move {
loop {
if let Some(fetch) = fetch_rx.recv().await {
info!("got clipboard lookup from writer, try pasting");
let mut bytes = Vec::new();
bytes.extend_from_slice(b"hello xorg");
let d = ClipboardData {
requested_type: fetch.requested_type,
data_type: None,
bytes,
remaining_bytes: 0,
};
if let Err(_d_again) = fetch.fetch_result_tx.send(d) {
error!("storing clipboard data failed");
}
}
}
});
info!("waiting for new clipboard types...");
clipboard_types_rx.changed().await?;
info!("got clipboard types A: {:?}", clipboard_types_rx.borrow());
x11_fetch_data(&mut reader, type_).await?;
{
let mut writer = writer.lock().await;
x11_store_types(&mut writer, &types).await?;
}
info!("waiting for new clipboard types again...");
clipboard_types_rx.changed().await?;
info!("got clipboard types B: {:?}", clipboard_types_rx.borrow());
x11_fetch_data(&mut reader, type_).await?;
info!("clearing clipboard types");
{
let mut writer = writer.lock().await;
x11_store_types(&mut writer, &vec![]).await?;
}
time::sleep(std::time::Duration::from_millis(500)).await;
info!("trying fetch after clear");
x11_fetch_data(&mut reader, type_).await?;
info!("try pasting again in the next 5s, it should do nothing");
time::sleep(std::time::Duration::from_millis(5000)).await;
Ok(())
}
async fn x11_store_types(clipboard: &mut ClipboardWriter, types: &Vec<&str>) -> Result<()> {
let types: Vec<String> = types.iter().map(|t| t.to_string()).collect();
let types_len = types.len();
clipboard.store_types(types)?;
info!("stored {} types into clipboard", types_len);
Ok(())
}
async fn x11_fetch_data(clipboard: &mut ClipboardReader, type_: &str) -> Result<()> {
let (val, _data_type) = clipboard.read(type_, 0, &None).await?;
if val.len() > 256 {
info!("got clipboard from x11: {} bytes", val.len());
} else {
info!(
"got clipboard from x11: {} bytes: [{}]",
val.len(),
String::from_utf8_lossy(&val)
);
}
Ok(())
}