Fix/clipboard retry if is occupied (#9293)

* fix: clipboard, retry if is occupied

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix: clipboard service, hold runtime to cm ipc

Signed-off-by: fufesou <linlong1266@gmail.com>

* update arboard

Signed-off-by: fufesou <linlong1266@gmail.com>

* refact: log

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix: get formats, return only not

Signed-off-by: fufesou <linlong1266@gmail.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
fufesou
2024-09-08 21:13:05 +08:00
committed by GitHub
parent 1e6944b380
commit 2922ebe22a
4 changed files with 70 additions and 19 deletions

View File

@@ -11,6 +11,8 @@ use std::{
sync::mpsc::{channel, RecvTimeoutError, Sender},
time::Duration,
};
#[cfg(windows)]
use tokio::runtime::Runtime;
struct Handler {
sp: EmptyExtraFieldService,
@@ -18,6 +20,8 @@ struct Handler {
tx_cb_result: Sender<CallbackResult>,
#[cfg(target_os = "windows")]
stream: Option<ipc::ConnectionTmpl<parity_tokio_ipc::ConnectionClient>>,
#[cfg(target_os = "windows")]
rt: Option<Runtime>,
}
pub fn new() -> GenericService {
@@ -34,6 +38,8 @@ fn run(sp: EmptyExtraFieldService) -> ResultType<()> {
tx_cb_result,
#[cfg(target_os = "windows")]
stream: None,
#[cfg(target_os = "windows")]
rt: None,
};
let (tx_start_res, rx_start_res) = channel();
@@ -129,29 +135,41 @@ impl Handler {
// 1. the clipboard is not used frequently.
// 2. the clipboard handle is sync and will not block the main thread.
#[cfg(windows)]
#[tokio::main(flavor = "current_thread")]
async fn read_clipboard_from_cm_ipc(&mut self) -> ResultType<Vec<ClipboardNonFile>> {
fn read_clipboard_from_cm_ipc(&mut self) -> ResultType<Vec<ClipboardNonFile>> {
if self.rt.is_none() {
self.rt = Some(Runtime::new()?);
}
let Some(rt) = &self.rt else {
// unreachable!
bail!("failed to get tokio runtime");
};
let mut is_sent = false;
if let Some(stream) = &mut self.stream {
// If previous stream is still alive, reuse it.
// If the previous stream is dead, `is_sent` will trigger reconnect.
is_sent = stream.send(&Data::ClipboardNonFile(None)).await.is_ok();
is_sent = match rt.block_on(stream.send(&Data::ClipboardNonFile(None))) {
Ok(_) => true,
Err(e) => {
log::debug!("Failed to send to cm: {}", e);
false
}
};
}
if !is_sent {
let mut stream = crate::ipc::connect(100, "_cm").await?;
stream.send(&Data::ClipboardNonFile(None)).await?;
let mut stream = rt.block_on(crate::ipc::connect(100, "_cm"))?;
rt.block_on(stream.send(&Data::ClipboardNonFile(None)))?;
self.stream = Some(stream);
}
if let Some(stream) = &mut self.stream {
loop {
match stream.next_timeout(800).await? {
match rt.block_on(stream.next_timeout(800))? {
Some(Data::ClipboardNonFile(Some((err, mut contents)))) => {
if !err.is_empty() {
bail!("{}", err);
} else {
if contents.iter().any(|c| c.next_raw) {
match timeout(1000, stream.next_raw()).await {
match rt.block_on(timeout(1000, stream.next_raw())) {
Ok(Ok(mut data)) => {
for c in &mut contents {
if c.next_raw {
@@ -168,7 +186,7 @@ impl Handler {
Err(e) => {
// Reconnect to avoid the next raw data remaining in the buffer.
self.stream = None;
log::debug!("failed to get raw clipboard data: {}", e);
log::debug!("Failed to get raw clipboard data: {}", e);
}
}
}