mirror of
https://github.com/icewind1991/clipboard-sync
synced 2026-06-03 10:24:06 +02:00
cleanup
This commit is contained in:
parent
96295ac0dc
commit
e84fe3467b
5 changed files with 190 additions and 71 deletions
56
Cargo.lock
generated
56
Cargo.lock
generated
|
|
@ -99,6 +99,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"clipboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"err-derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -155,6 +156,18 @@ dependencies = [
|
|||
"termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "err-derive"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fake-simd"
|
||||
version = "0.1.2"
|
||||
|
|
@ -595,6 +608,14 @@ dependencies = [
|
|||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "0.2.8"
|
||||
|
|
@ -628,6 +649,19 @@ dependencies = [
|
|||
"core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.92"
|
||||
|
|
@ -643,7 +677,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -679,7 +713,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.36"
|
||||
version = "0.15.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -687,6 +721,17 @@ dependencies = [
|
|||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.0.8"
|
||||
|
|
@ -888,6 +933,7 @@ dependencies = [
|
|||
"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
|
||||
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
|
||||
"checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a"
|
||||
"checksum err-derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3d8ff65eb6c2fc68e76557239d16f5698fd56603925b89856d3f0f7105fd4543"
|
||||
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
|
@ -942,17 +988,21 @@ dependencies = [
|
|||
"checksum regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b2f0808e7d7e4fb1cb07feb6ff2f4bc827938f24f8c2e6a3beb7370af544bdd"
|
||||
"checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48"
|
||||
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f"
|
||||
"checksum schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f6abf258d99c3c1c5c2131d99d064e94b7b3dd5f416483057f308fea253339"
|
||||
"checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2"
|
||||
"checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be"
|
||||
"checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e"
|
||||
"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
|
||||
"checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68"
|
||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
|
||||
"checksum syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)" = "8b4f551a91e2e3848aeef8751d0d4eec9489b6474c720fd4c55958d8d31a430c"
|
||||
"checksum syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)" = "ec52cd796e5f01d0067225a5392e70084acc4c0013fa71d55166d38a8b307836"
|
||||
"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
|
||||
"checksum tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef"
|
||||
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
|
||||
"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330"
|
||||
|
|
|
|||
|
|
@ -19,3 +19,4 @@ serde_json = "1.0"
|
|||
clipboard = "0.5"
|
||||
env_logger = "0.6"
|
||||
ws = {version = "0.8", features = ["native-tls"]}
|
||||
err-derive = "0.1"
|
||||
|
|
@ -1,26 +1,28 @@
|
|||
use clipboard::{ClipboardContext, ClipboardProvider};
|
||||
use crate::common::ClipboardCommand;
|
||||
use std::{thread, thread::JoinHandle, time};
|
||||
use clipboard::{ClipboardContext, ClipboardProvider};
|
||||
use std::convert::TryFrom;
|
||||
use std::env;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
use std::{thread, thread::JoinHandle};
|
||||
use ws::{connect, Message, Sender};
|
||||
|
||||
mod common;
|
||||
|
||||
fn handle_command(command: ClipboardCommand, ctx: &mut ClipboardContext, current_clipboard: Arc<Mutex<String>>) {
|
||||
match command {
|
||||
ClipboardCommand::Set { value, session: _ } => {
|
||||
let mut clip = current_clipboard.lock().unwrap();
|
||||
if *clip != value {
|
||||
let _ = ctx.set_contents(value.clone());
|
||||
*clip = value;
|
||||
}
|
||||
fn handle_command(
|
||||
command: ClipboardCommand,
|
||||
ctx: &mut ClipboardContext,
|
||||
current_clipboard: Arc<Mutex<String>>,
|
||||
) {
|
||||
if let ClipboardCommand::Set { value, session: _ } = command {
|
||||
let mut clip = current_clipboard.lock().unwrap();
|
||||
if *clip != value {
|
||||
let _ = ctx.set_contents(value.clone());
|
||||
*clip = value;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
let args: Vec<_> = env::args().collect();
|
||||
|
|
@ -41,41 +43,52 @@ fn main() {
|
|||
|
||||
move |msg: Message| {
|
||||
let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
|
||||
let result: serde_json::Result<ClipboardCommand> = serde_json::from_str(msg.as_text().unwrap_or_default());
|
||||
match result {
|
||||
Ok(command) => handle_command(command, &mut ctx, current_clipboard.clone()),
|
||||
Err(_) => {}
|
||||
if let Ok(command) = ClipboardCommand::try_from(msg) {
|
||||
handle_command(command, &mut ctx, current_clipboard.clone());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn clipboard_thread(session: String, out: Sender, current_clipboard: Arc<Mutex<String>>) -> JoinHandle<()> {
|
||||
const HUNDRED_MS: Duration = Duration::from_millis(100);
|
||||
|
||||
fn clipboard_thread(
|
||||
session: String,
|
||||
out: Sender,
|
||||
current_clipboard: Arc<Mutex<String>>,
|
||||
) -> JoinHandle<()> {
|
||||
thread::spawn(move || {
|
||||
let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
|
||||
let hundred_millis = time::Duration::from_millis(100);
|
||||
|
||||
{
|
||||
let mut clip = current_clipboard.lock().unwrap();
|
||||
*clip = ctx.get_contents().unwrap_or_default();
|
||||
}
|
||||
|
||||
thread::sleep(hundred_millis);
|
||||
thread::sleep(HUNDRED_MS);
|
||||
|
||||
// we need to do the listen after returning the closure for the websocket
|
||||
// thus we can't send this message in the factory
|
||||
send_to_server(&out, &ClipboardCommand::Listen {
|
||||
session: session.clone()
|
||||
});
|
||||
send_to_server(
|
||||
&out,
|
||||
&ClipboardCommand::Listen {
|
||||
session: session.clone(),
|
||||
},
|
||||
);
|
||||
loop {
|
||||
thread::sleep(hundred_millis);
|
||||
thread::sleep(HUNDRED_MS);
|
||||
let new_clipboard = ctx.get_contents().unwrap_or_default();
|
||||
let mut clip = current_clipboard.lock().unwrap();
|
||||
if *clip != new_clipboard {
|
||||
send_to_server(&out, &ClipboardCommand::Set {
|
||||
session: session.clone(),
|
||||
value: new_clipboard.clone(),
|
||||
});
|
||||
send_to_server(
|
||||
&out,
|
||||
&ClipboardCommand::Set {
|
||||
session: session.clone(),
|
||||
value: new_clipboard.clone(),
|
||||
},
|
||||
);
|
||||
*clip = new_clipboard;
|
||||
}
|
||||
}
|
||||
|
|
@ -83,6 +96,5 @@ fn clipboard_thread(session: String, out: Sender, current_clipboard: Arc<Mutex<S
|
|||
}
|
||||
|
||||
fn send_to_server(out: &Sender, command: &ClipboardCommand) {
|
||||
let command_text = serde_json::to_string(command).unwrap();
|
||||
out.send(Message::from(command_text.clone())).ok();
|
||||
}
|
||||
let _ = out.send(command);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,53 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
use err_derive::Error;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{from_str, to_string, Error as SerdeError};
|
||||
use std::convert::TryFrom;
|
||||
use ws::{Error as WsError, ErrorKind, Message};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(tag = "type")]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ClipboardCommand {
|
||||
#[serde(rename = "listen")]
|
||||
Listen { session: String },
|
||||
#[serde(rename = "set")]
|
||||
Set { session: String, value: String }
|
||||
}
|
||||
Set { session: String, value: String },
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ParseError {
|
||||
#[error(display = "Invalid message encoding")]
|
||||
Encoding,
|
||||
#[error(display = "Invalid formatted message: {}", _1)]
|
||||
InvalidMessage(#[error(cause)] SerdeError, String),
|
||||
#[error(display = "Unknown error")]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl From<WsError> for ParseError {
|
||||
fn from(from: WsError) -> Self {
|
||||
match from.kind {
|
||||
ErrorKind::Encoding(_) => ParseError::Encoding,
|
||||
_ => ParseError::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Message> for ClipboardCommand {
|
||||
type Error = ParseError;
|
||||
|
||||
fn try_from(msg: Message) -> Result<Self, Self::Error> {
|
||||
let text = msg.as_text()?;
|
||||
from_str::<ClipboardCommand>(text)
|
||||
.map_err(|err| ParseError::InvalidMessage(err, text.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ClipboardCommand> for Message {
|
||||
fn from(command: ClipboardCommand) -> Self {
|
||||
Message::from(&command)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&ClipboardCommand> for Message {
|
||||
fn from(command: &ClipboardCommand) -> Self {
|
||||
Message::from(to_string(command).unwrap())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,34 +2,47 @@ use crate::common::ClipboardCommand;
|
|||
use mio::Token;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::rc::Rc;
|
||||
use ws::{CloseCode, Error, Handler, listen, Message, Result, Sender};
|
||||
use ws::{listen, CloseCode, Error, Handler, Message, Result, Sender};
|
||||
|
||||
mod common;
|
||||
|
||||
#[derive(Default)]
|
||||
struct Session {
|
||||
clients: HashMap<Token, Sender>
|
||||
clients: HashMap<Token, Sender>,
|
||||
}
|
||||
|
||||
fn handle_command(command: ClipboardCommand, sessions: &mut HashMap<String, Session>, client: Sender) {
|
||||
match command {
|
||||
ClipboardCommand::Listen { session: session_name } => {
|
||||
sessions.entry(session_name).or_insert_with(|| Session {
|
||||
clients: HashMap::new()
|
||||
}).clients.insert(client.token(), client);
|
||||
impl Session {
|
||||
pub fn join(&mut self, client: Sender) {
|
||||
self.clients.insert(client.token(), client);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_command(
|
||||
command: ClipboardCommand,
|
||||
sessions: &mut HashMap<String, Session>,
|
||||
client: &Sender,
|
||||
) {
|
||||
match &command {
|
||||
ClipboardCommand::Listen {
|
||||
session: session_name,
|
||||
} => {
|
||||
sessions
|
||||
.entry(session_name.clone())
|
||||
.or_default()
|
||||
.join(client.clone());
|
||||
}
|
||||
|
||||
ClipboardCommand::Set { value, session: session_name } => {
|
||||
match sessions.get_mut(&session_name) {
|
||||
Some(session) => {
|
||||
send_to_session(session, &ClipboardCommand::Set {
|
||||
value,
|
||||
session: session_name,
|
||||
}, client.token());
|
||||
}
|
||||
None => println!("session {} not found", session_name)
|
||||
ClipboardCommand::Set {
|
||||
value: _,
|
||||
session: session_name,
|
||||
} => match sessions.get_mut(session_name) {
|
||||
Some(session) => {
|
||||
send_to_session(session, &command, client.token());
|
||||
}
|
||||
}
|
||||
None => println!("session {} not found", session_name),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -37,12 +50,11 @@ fn send_to_session(session: &Session, command: &ClipboardCommand, exclude: Token
|
|||
let command_text = serde_json::to_string(command).unwrap();
|
||||
for client in session.clients.values() {
|
||||
if client.token() != exclude {
|
||||
client.send(Message::from(command_text.clone())).ok();
|
||||
let _ = client.send(command_text.as_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct Server {
|
||||
out: Sender,
|
||||
sessions: Rc<RefCell<HashMap<String, Session>>>,
|
||||
|
|
@ -50,17 +62,15 @@ struct Server {
|
|||
|
||||
impl Handler for Server {
|
||||
fn on_message(&mut self, msg: Message) -> Result<()> {
|
||||
let result: serde_json::Result<ClipboardCommand> = serde_json::from_str(msg.as_text().unwrap_or_default());
|
||||
match result {
|
||||
match ClipboardCommand::try_from(msg) {
|
||||
Ok(command) => {
|
||||
handle_command(command, &mut self.sessions.borrow_mut(), self.out.clone());
|
||||
Ok(())
|
||||
handle_command(command, &mut self.sessions.borrow_mut(), &self.out);
|
||||
}
|
||||
Err(_) => {
|
||||
println!("invalid message: {}", msg.as_text().unwrap_or_default());
|
||||
Ok(())
|
||||
Err(err) => {
|
||||
println!("{}", err);
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_close(&mut self, _: CloseCode, _: &str) {
|
||||
|
|
@ -85,11 +95,14 @@ fn main() {
|
|||
|
||||
let sessions: Rc<RefCell<HashMap<String, Session>>> = Rc::new(RefCell::new(HashMap::new()));
|
||||
|
||||
let result = listen(listen_address, |out| { Server { out, sessions: sessions.clone() } });
|
||||
let result = listen(listen_address, |out| Server {
|
||||
out,
|
||||
sessions: sessions.clone(),
|
||||
});
|
||||
match result {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
println!("error while listening");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue