commit 9744166dca14bf46458b156f0c06ad0efe89939d Author: Surferlul Date: Wed Jul 20 02:19:12 2022 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..afda37b --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,203 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "evdev" +version = "0.11.5" +dependencies = [ + "bitvec", + "libc", + "nix 0.23.1", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "nix" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "nix" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "remote-evdev" +version = "0.1.0" +dependencies = [ + "byteorder", + "evdev", + "nix 0.24.2", + "ron", +] + +[[package]] +name = "ron" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" +dependencies = [ + "base64", + "bitflags", + "serde", +] + +[[package]] +name = "serde" +version = "1.0.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "unicode-ident" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" + +[[package]] +name = "wyz" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e" +dependencies = [ + "tap", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..27adf40 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "remote-evdev" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +evdev = "0.11.4" +ron = "*" +byteorder = "1.4.3" +nix = "0.24.2" + +[patch.crates-io] +evdev = { path = "evdev" } \ No newline at end of file diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..2a3aa41 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,92 @@ +use std::env; +use std::path::Path; + +pub struct DeviceInfo { + pub path: String, + pub device_type: String +} + +pub struct NetConfig { + pub is_server: bool, + pub is_host: bool, + pub port: i32, + pub ip_address: String +} + +pub fn get_config() -> (NetConfig, Vec) { + let args: Vec = env::args().collect(); + + let mut context = ""; + let mut cfg = NetConfig { + is_server: false, + is_host: true, + port: 64654, + ip_address: String::from("auto") + }; + let mut devices_info = Vec::new(); + for i in &args[1..] { + match i.as_str() { + "-s" | "--server" => cfg.is_server = true, + "-c" | "--client" => cfg.is_server = false, + "-h" | "--host" => cfg.is_host = true, + "-g" | "--guest" => cfg.is_host = false, + "-p" | "--port" => context = "port", + "-a" | "--ip-address" => context = "ip_address", + "-d" | "--device" => { + context = "device"; + devices_info.push(DeviceInfo { + path: String::from(""), + device_type: String::from("other") + }); + }, + "--id" => context = "device_id", + "--path" => context = "device_path", + "--event" => context = "device_event", + "--full-path" => context = "device_full_path", + "--type" => context = "device_type", + &_ => { + if context.starts_with("device") { + let (key, tmp) = match context { + "device_id" => ("path", "/dev/input/by-id/"), + "device_path" => ("path", "/dev/input/by-path/"), + "device_event" => ("path", "/dev/input/"), + "device_full_path" => ("path", ""), + "device_type" => { + match i.as_str() { + "pointer" | "keyboard" => ("type", ""), + &_ => panic!("Invalid device type {}!", i.as_str()) + } + }, + &_ => panic!("Unknown context!") + }; + let mut value = tmp.to_owned(); + let mut device_info = devices_info.last_mut().unwrap(); + if key == "path" { + value = format!("{}{}", value, i); + if !Path::new(value.as_str()).exists() { + panic!("Path {} does not exist!", value) + } + device_info.path = value; + } else if key == "type" { + device_info.device_type = key.to_owned(); + } + } else { + match context { + "port" => { + match i.parse::() { + Ok(num) => cfg.port = num, + Err(_) => panic!("Invalid port value!") + } + }, + "ip_address" => cfg.ip_address = i.to_owned(), + &_ => panic!("Invalid context!") + } + } + }, + } + } + if cfg.ip_address == "auto" { + panic!("Not implemented yet!") + } + return (cfg, devices_info); +} \ No newline at end of file diff --git a/src/epoll_struct.rs b/src/epoll_struct.rs new file mode 100644 index 0000000..ebae0a3 --- /dev/null +++ b/src/epoll_struct.rs @@ -0,0 +1,21 @@ +use std::os::unix::io::{AsRawFd, RawFd}; + +pub struct Epoll(RawFd); + +impl Epoll { + pub(crate) fn new(fd: RawFd) -> Self { + Epoll(fd) + } +} + +impl AsRawFd for Epoll { + fn as_raw_fd(&self) -> RawFd { + self.0 + } +} + +impl Drop for Epoll { + fn drop(&mut self) { + let _ = nix::unistd::close(self.0); + } +} \ No newline at end of file diff --git a/src/handle_client/handle_guest.rs b/src/handle_client/handle_guest.rs new file mode 100644 index 0000000..605704f --- /dev/null +++ b/src/handle_client/handle_guest.rs @@ -0,0 +1,55 @@ +use std::io::prelude::*; +use std::net::TcpStream; +use byteorder::{BigEndian, ReadBytesExt}; +use evdev::{ + InputEvent, + uinput::VirtualDevice +}; + +use crate::{ + manage_device::deserialize::{ + deserialize_device::build_virtual_device, + deserialize_input_event + } +}; + +fn receive_device(mut stream: &TcpStream) -> std::io::Result> { + let buf_size = stream.read_u64::()?; + if buf_size == 0 { + return Ok(None) + }; + let mut buf = vec![0; buf_size as usize]; + stream.read_exact(&mut buf)?; + let data = String::from_utf8(buf).expect("Couldn't decode utf8"); + Ok(Some(build_virtual_device(data))) +} + +fn receive_input_event(mut stream: &TcpStream) -> std::io::Result<(usize, InputEvent)> { + Ok( + ( + stream.read_u64::()? as usize, + deserialize_input_event( + ( + stream.read_u16::()?, + stream.read_u16::()?, + stream.read_i32::()? + ) + ) + ) + ) +} + +pub fn handle_client(stream: TcpStream) -> std::io::Result<()>{ + let mut devices = Vec::new(); + while let Some(device) = receive_device(&stream)? { + devices.push(device); + } + loop { + let (device_id, input_event) = receive_input_event(&stream)?; + if device_id as u64 == u32::MAX as u64 { + break + } + devices[device_id].emit_raw(&[input_event]).expect("Couldn't emit input event"); + } + Ok(()) +} \ No newline at end of file diff --git a/src/handle_client/handle_host/device_collection.rs b/src/handle_client/handle_host/device_collection.rs new file mode 100644 index 0000000..2aa5a73 --- /dev/null +++ b/src/handle_client/handle_host/device_collection.rs @@ -0,0 +1,81 @@ +use evdev::{Device, InputEvent}; + +use crate::manage_device::set_unblocking; + +pub struct FetchDevicesEventsSynced<'a> { + collection: &'a mut DeviceCollection +} + +impl <'a>Iterator for FetchDevicesEventsSynced<'a> { + + type Item = Vec<(usize, InputEvent)>; + + fn next(&mut self) -> Option { + let mut events = Vec::new(); + for device_id in 0..self.collection.len() { + match self.collection[device_id].fetch_events() { + Ok(events_fetch) => { + for event in events_fetch { + events.push((device_id, event)) + } + }, + Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => { + } + Err(e) => { + eprintln!("{}", e); + return None + } + } + }; + Some(events) + } +} + +pub struct DeviceCollection { + pub devices: Vec +} + +impl DeviceCollection { + pub fn new() -> DeviceCollection { + DeviceCollection { + devices: Vec::new() + } + } + + pub fn push(&mut self, mut device: Device) { + set_unblocking(&mut device); + device.grab().expect("Couldn't grab device!"); + self.devices.push(device); + } + + pub fn len(&mut self) -> usize { + self.devices.len() + } + + pub fn fetch_events(&mut self) -> FetchDevicesEventsSynced { + FetchDevicesEventsSynced {collection: self} + } +} + +impl IntoIterator for DeviceCollection { + type Item = Device; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.devices.into_iter() + } +} + +impl std::ops::Index for DeviceCollection { + type Output = Device; + + fn index(&self, index: usize) -> &Self::Output { + &self.devices[index] + } +} + +impl std::ops::IndexMut for DeviceCollection { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.devices[index] + } +} \ No newline at end of file diff --git a/src/handle_client/handle_host/mod.rs b/src/handle_client/handle_host/mod.rs new file mode 100644 index 0000000..1ad7bb4 --- /dev/null +++ b/src/handle_client/handle_host/mod.rs @@ -0,0 +1,62 @@ +use std::io::prelude::*; +use std::net::TcpStream; +use evdev::{ + Device, + InputEvent +}; +use byteorder::{BigEndian, WriteBytesExt}; + +mod device_collection; + +use crate::{ + config::DeviceInfo, + manage_device::serialize::{ + serialize_device::serialize, + serialize_input_event + }, + handle_client::handle_host::device_collection::DeviceCollection +}; + +fn send_device(mut stream: &TcpStream, device: &mut Device) -> std::io::Result<()>{ + let buf = serialize(&device); + let buf_len = buf.as_bytes().len() as u64; + stream.write_u64::(buf_len)?; + stream.write(buf.as_bytes())?; + Ok(()) +} + +fn send_input_event(mut stream: &TcpStream, device_id: usize, input_event: InputEvent) -> std::io::Result<()> { + let data = serialize_input_event(input_event); + stream.write_u64::(device_id as u64)?; + stream.write_u16::(data.0)?; + stream.write_u16::(data.1)?; + stream.write_i32::(data.2)?; + Ok(()) +} + +pub fn handle_client(mut stream: TcpStream, devices_info: &Vec) -> std::io::Result<()>{ + let mut collection = DeviceCollection::new(); + for device_info in devices_info { + match Device::open(&device_info.path) { + Ok(device) => collection.push(device), + Err(_) => panic!("Couldn't open device {}", device_info.path) + } + } + for device in collection.devices.iter_mut() { + send_device(&stream, device)?; + } + stream.write_u64::(0)?; + for events in collection.fetch_events() { + for (device_id, event) in events { + send_input_event(&stream, device_id, event)?; + } + } + stream.write_u64::(u32::MAX as u64)?; + stream.write_u16::(0)?; + stream.write_u16::(0)?; + stream.write_i32::(0)?; + for device in collection.devices.iter_mut() { + device.ungrab().expect("Couldn't ungrab device {}!"); + } + Ok(()) +} \ No newline at end of file diff --git a/src/handle_client/mod.rs b/src/handle_client/mod.rs new file mode 100644 index 0000000..ea2a51a --- /dev/null +++ b/src/handle_client/mod.rs @@ -0,0 +1,14 @@ +use std::net::TcpStream; + +mod handle_host; +mod handle_guest; + +use crate::config::{NetConfig, DeviceInfo}; + +pub fn handle_client(stream: TcpStream, cfg: &NetConfig, devices_info: &Vec) { + if cfg.is_host { + crate::handle_client::handle_host::handle_client(stream, devices_info).expect("Couldn't write to stream") + } else { + crate::handle_client::handle_guest::handle_client(stream).expect("Couldn't read from stream") + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..48b4c47 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,24 @@ +#![feature(generic_associated_types)] + +mod config; +mod epoll_struct; +mod streams; +mod handle_client; +mod manage_device; + +use crate::{ + config::{ + get_config, + }, + streams::get_streams, + handle_client::handle_client, +}; + + +fn main() { + let (cfg, devices_info) = get_config(); + let ip = format!("{}:{}", cfg.ip_address, cfg.port); + for stream in get_streams(cfg.is_server, ip) { + handle_client(stream, &cfg, &devices_info); + } +} \ No newline at end of file diff --git a/src/manage_device/deserialize/deserialize_device.rs b/src/manage_device/deserialize/deserialize_device.rs new file mode 100644 index 0000000..521bae9 --- /dev/null +++ b/src/manage_device/deserialize/deserialize_device.rs @@ -0,0 +1,94 @@ +use std::ops::DerefMut; +use ron::de::from_str; +use evdev::{ + Key, + InputId, + SwitchType, + RelativeAxisType, + BusType, + AttributeSet, + AttributeSetRef, + uinput::{ + VirtualDevice, + VirtualDeviceBuilder + } +}; + + +fn deserialize_name(data: &str) -> String { + from_str(data).expect("Couldn't deserialize name!") +} + +fn deserialize_input_id(data: &str) -> InputId { + let vals: [u16; 4] = from_str(data).expect("Couldn't deserialize InputId!"); + InputId::new(BusType(vals[0]), vals[1], vals[2], vals[3]) +} + +fn deserialize_supported_keys(data: &str, keys: &mut AttributeSetRef) { + let vals: Vec = from_str(data).expect("Couldn't deserialize supported keys!"); + for key in vals.iter().map(|x| Key(*x)) { + keys.insert(key); + } +} + +fn deserialize_supported_relative_axes(data: &str, relative_axes: &mut AttributeSetRef) -> Result<(), &'static str> { + match from_str::>>(data).expect("Couldn't deserialize relative axes") { + Some(vals) => { + for rel_axes_type in vals.iter().map(|x| RelativeAxisType(*x)) { + relative_axes.insert(rel_axes_type); + } + Ok(()) + }, + None => Err("No relative axes support"), + } +} + +fn deserialize_supported_switches(data: &str, switches: &mut AttributeSetRef) -> Result<(), &'static str> { + match from_str::>>(data).expect("Couldn't deserialize relative axes") { + Some(vals) => { + for switch_type in vals.iter().map(|x| SwitchType(*x)) { + switches.insert(switch_type); + } + Ok(()) + }, + None => Err("No switch support"), + } +} + +fn deserialize( + data: String, + keys: &mut AttributeSetRef, + relative_axes: &mut AttributeSetRef, + switches: &mut AttributeSetRef +) -> (String, InputId, Result<(), &'static str>, Result<(), &'static str>) { + let de_data: [String; 5] = from_str(data.as_str()).expect("Couldn't deserialize device!"); + let name = deserialize_name(de_data[0].as_str()); + let input_id = deserialize_input_id(de_data[1].as_str()); + deserialize_supported_keys(de_data[2].as_str(), keys); + ( + name, + input_id, + deserialize_supported_relative_axes(de_data[3].as_str(), relative_axes), + deserialize_supported_switches(de_data[4].as_str(), switches) + ) +} + +pub fn build_virtual_device(data: String) -> VirtualDevice { + let mut keys: AttributeSet = AttributeSet::new(); + let mut relative_axes: AttributeSet = AttributeSet::new(); + let mut switches: AttributeSet = AttributeSet::new(); + let (name, input_id, relative_axes_support, switch_support) = deserialize(data, keys.deref_mut(), relative_axes.deref_mut(), switches.deref_mut()); + let mut uinput_builder = VirtualDeviceBuilder::new().expect("Couldn't create new virtual device builder!") + .name(name.as_str()) + .input_id(input_id) + .with_keys(keys.deref_mut()).expect("Couldn't build virtual device with keys!"); + match relative_axes_support { + Ok(_) => {}, + Err(_) => uinput_builder = uinput_builder.with_relative_axes(relative_axes.deref_mut()).expect("Couldn't build virtual device with relative axes!") + } + match switch_support { + Ok(_) => {}, + Err(_) => uinput_builder = uinput_builder.with_switches(switches.deref_mut()).expect("Couldn't build virtual device with switches!") + } + uinput_builder.build().expect("Couldn't build virtual device!") +} \ No newline at end of file diff --git a/src/manage_device/deserialize/mod.rs b/src/manage_device/deserialize/mod.rs new file mode 100644 index 0000000..99ada77 --- /dev/null +++ b/src/manage_device/deserialize/mod.rs @@ -0,0 +1,10 @@ +use evdev::{ + InputEvent, + EventType +}; + +pub mod deserialize_device; + +pub fn deserialize_input_event(data: (u16, u16, i32)) -> InputEvent { + InputEvent::new(EventType(data.0), data.1, data.2) +} \ No newline at end of file diff --git a/src/manage_device/mod.rs b/src/manage_device/mod.rs new file mode 100644 index 0000000..dc16168 --- /dev/null +++ b/src/manage_device/mod.rs @@ -0,0 +1,35 @@ +use std::os::unix::io::AsRawFd; +use evdev::Device; +use nix::{ + fcntl::{FcntlArg, OFlag}, + sys::epoll, +}; + +pub mod serialize; +pub mod deserialize; + +use crate::{ + epoll_struct::Epoll, +}; + +pub fn set_unblocking(device: &mut Device) { + let raw_fd = device.as_raw_fd(); + // Set nonblocking + nix::fcntl::fcntl(raw_fd, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)).expect("Couldn't set nonblocking!"); + + //Create epoll handle and attach raw_fd + let epoll_fd = Epoll::new(epoll::epoll_create1( + epoll::EpollCreateFlags::EPOLL_CLOEXEC, + ).expect("Couldn't create epoll handle!")); + let mut event = epoll::EpollEvent::new(epoll::EpollFlags::EPOLLIN, 0); + epoll::epoll_ctl( + epoll_fd.as_raw_fd(), + epoll::EpollOp::EpollCtlAdd, + raw_fd, + Some(&mut event), + ).expect("Couldn't attach raw_fd to epoll!"); + + // We don't care about these, but the kernel wants to fill them. + let _events = [epoll::EpollEvent::empty(); 2]; + +} \ No newline at end of file diff --git a/src/manage_device/serialize/mod.rs b/src/manage_device/serialize/mod.rs new file mode 100644 index 0000000..1e2a737 --- /dev/null +++ b/src/manage_device/serialize/mod.rs @@ -0,0 +1,7 @@ +use evdev::InputEvent; + +pub mod serialize_device; + +pub fn serialize_input_event(event: InputEvent) -> (u16, u16, i32) { + (event.event_type().0, event.code(), event.value()) +} \ No newline at end of file diff --git a/src/manage_device/serialize/serialize_device.rs b/src/manage_device/serialize/serialize_device.rs new file mode 100644 index 0000000..ffa6983 --- /dev/null +++ b/src/manage_device/serialize/serialize_device.rs @@ -0,0 +1,60 @@ +use ron::ser::to_string; +use evdev::Device; + +fn serialize_name(device: &Device) -> String { + to_string( + device.name().unwrap() + ).expect("Error serializing name!") +} + +fn serialize_input_id(device: &Device) -> String { + let input_id = device.input_id(); + to_string( + &[ + input_id.bus_type().0, + input_id.vendor(), + input_id.product(), + input_id.version() + ] + ).expect("Error serializing InputId!") +} + +fn serialize_supported_keys(device: &Device) -> String { + to_string( + &device.supported_keys().unwrap().iter().map(|x| x.0).collect::>() + ).expect("Error serializing supported_keys!") +} + +fn serialize_supported_relative_axes(device: &Device) -> String { + to_string::>>( + &match device.supported_relative_axes() { + Some(relative_axes) => Some( + relative_axes.iter().map(|x| x.0).collect::>() + ), + None => None + } + ).expect("Error serializing supported_relative_axes!") +} + +fn serialize_supported_switches(device: &Device) -> String { + to_string::>>( + &match device.supported_switches() { + Some(switches) => Some( + switches.iter().map(|x| x.0).collect::>() + ), + None => None + } + ).expect("Error serializing supported_switches!") +} + +pub fn serialize(device: &Device) -> String { + to_string( + &[ + serialize_name(device), + serialize_input_id(device), + serialize_supported_keys(device), + serialize_supported_relative_axes(device), + serialize_supported_switches(device) + ] + ).expect("Error serializing device!") +} \ No newline at end of file diff --git a/src/streams.rs b/src/streams.rs new file mode 100644 index 0000000..d685c4a --- /dev/null +++ b/src/streams.rs @@ -0,0 +1,55 @@ +use std::net::{TcpListener, TcpStream}; + +pub struct StreamIter { + ip: String, + is_server: bool, + listener: Option, +} + +impl Iterator for StreamIter { + + type Item = TcpStream; + + fn next(&mut self) -> Option { + if self.is_server { + let mut incoming = match self.listener.as_mut() { + Some(listener) => listener.incoming(), + None => { + self.listener = Some(match TcpListener::bind(self.ip.as_str()) { + Ok(listener) => listener, + Err(_) => panic!("Unable to bind to {}", self.ip) + }); + self.listener.as_mut().unwrap().incoming() + } + }; + println!("Waiting for connection from client"); + match incoming.next() { + Some(stream) => match stream { + Ok(client) => { + println!("Connection established"); + Some(client) + }, + Err(_) => panic!("Unable to get stream") + }, + None => None + } + } else { + println!("Connecting to server"); + match TcpStream::connect(self.ip.as_str()) { + Ok(client) => { + println!("Connection established"); + Some(client) + }, + Err(_) => panic!("Unable to connect to {}:", self.ip) + } + } + } +} + +pub fn get_streams(is_server: bool, ip: String) -> StreamIter { + StreamIter { + ip, + is_server, + listener: None, + } +} \ No newline at end of file