rusty-pipe/src/engine.rs

252 lines
6.9 KiB
Rust

use crate::config::Engine;
use hidapi::HidApi;
use rusb::UsbContext;
use gilrs::{Gilrs, Button, Event};
pub trait InputEngine {
fn get(&mut self) -> Vec<char>;
}
pub fn build_input_engine(cfg: &Engine) -> Result<Box<dyn InputEngine>, String> {
match cfg.name.as_str() {
"stdin" => return Ok(Box::new(InputEngineStdin{})),
"kafka" => return build_input_engine_kafka(&cfg),
"udp" => return build_input_engine_udp(&cfg),
"device" => return build_input_engine_device(&cfg),
_ => return Err("unknown input engine name".to_string() + &cfg.name),
}
}
struct InputEngineDevice {
}
pub fn build_input_engine_device(cfg: &Engine) -> Result<Box<dyn InputEngine>, String> {
return build_input_engine_device_gilrs(cfg)
}
pub fn build_input_engine_device_gilrs(cfg: &Engine) -> Result<Box<dyn InputEngine>, String> {
let _device_cfg = cfg.device.as_ref().unwrap();
let mut gilrs = Gilrs::new().unwrap();
println!("printing gamepads");
for (_id, gamepad) in gilrs.gamepads() {
println!("{} is {:?}", gamepad.name(), gamepad.power_info());
}
println!("printing gamepads events");
loop {
// println!("reading gamepads events");
// Examine new events
while let Some(Event { id, event, time }) = gilrs.next_event() {
println!("{:?} New event from {}: {:?}", time, id, event);
let active_gamepad = Some(id);
println!("inspecting event");
// You can also use cached gamepad state
if let Some(gamepad) = active_gamepad.map(|id| gilrs.gamepad(id)) {
if gamepad.is_pressed(Button::South) {
println!("Button South is pressed (XBox - A, PS - X)");
}
}
break;
}
std::thread::sleep(std::time::Duration::from_millis(15));
break;
}
return Err("do what".to_string());
}
pub fn build_input_engine_device_hidapi(cfg: &Engine) -> Result<Box<dyn InputEngine>, String> {
let _device_cfg = cfg.device.as_ref().unwrap();
match HidApi::new() {
Ok(api) => {
for device in api.devices() {
println!("{:#?}", device);
}
},
Err(e) => {
eprintln!("Error: {}", e);
},
};
return Err("do what".to_string());
}
pub fn build_input_engine_device_rusb(cfg: &Engine) -> Result<Box<dyn InputEngine>, String> {
let _device_cfg = cfg.device.as_ref().unwrap();
assert!(rusb::has_capability());
let ctx = rusb::Context::new().unwrap();
assert!(ctx.devices().unwrap().len() > 0);
for device in ctx.devices().unwrap().iter() {
let device_desc = device.device_descriptor().unwrap();
println!("Bus {:03} Device {:03} ID {:04x}:{:04x}",
device.bus_number(),
device.address(),
device_desc.vendor_id(),
device_desc.product_id());
}
return Err("do what".to_string());
}
impl InputEngine for InputEngineDevice {
fn get(&mut self) -> Vec<char> {
Err("end".to_string()).unwrap()
}
}
struct InputEngineUDP {
last_socket: Option<std::net::UdpSocket>,
port: i32,
}
pub fn build_input_engine_udp(cfg: &Engine) -> Result<Box<dyn InputEngine>, String> {
let udp_cfg = cfg.udp.as_ref().unwrap();
return Ok(Box::new(InputEngineUDP{
last_socket: None,
port: udp_cfg.port,
}));
}
impl InputEngine for InputEngineUDP {
fn get(&mut self) -> Vec<char> {
let addr = "0.0.0.0:".to_string() + &self.port.to_string();
println!("$ echo -n 'hello world' | nc -4u -w0 localhost {}", &self.port.to_string());
if self.last_socket.is_none() {
self.last_socket = Some(std::net::UdpSocket::bind(addr).unwrap());
}
let result = self._get();
if result.is_err() {
self.last_socket = None;
return Vec::<char>::new();
}
return result.unwrap();
}
}
impl InputEngineUDP {
fn _get(&mut self) -> Result<Vec<char>, std::io::Error> {
let mut buf = [0; 128];
let socket = self.last_socket.ok_or(std::io::Error::new(std::io::ErrorKind::Other, "no socket"))?;
let (amt, _) = socket.recv_from(&mut buf)?;
let buf = &mut buf[..amt];
return Ok(std::str::from_utf8(buf).unwrap().chars().collect());
}
}
struct InputEngineKafka {
}
pub fn build_input_engine_kafka(cfg: &Engine) -> Result<Box<dyn InputEngine>, String> {
let _kafka_cfg = cfg.kafka.as_ref().unwrap();
return Err("do what".to_string());
}
impl InputEngine for InputEngineKafka {
fn get(&mut self) -> Vec<char> {
Err("end".to_string()).unwrap()
}
}
struct InputEngineStdin {}
impl InputEngine for InputEngineStdin {
fn get(&mut self) -> Vec<char> {
let stdin = std::io::stdin();
let mut result = String::new();
stdin.read_line(&mut result).unwrap();
return result.trim().chars().collect();
}
}
#[cfg(test)]
mod test_input {
use super::*;
struct InputEngineTest {}
impl InputEngine for InputEngineTest {
fn get(&mut self) -> Vec<char> {
return "hello world".chars().collect();
}
}
#[test]
fn test_input_engine_impl() {
let mut input_engine_test = InputEngineTest{};
_test_input_engine_impl(&mut input_engine_test);
}
fn _test_input_engine_impl(engine: &mut dyn InputEngine) {
assert_eq!("hello world".to_string(), engine.get().iter().cloned().collect::<String>());
}
}
pub trait OutputEngine {
fn put(&self, v: Vec<char>);
}
pub fn build_output_engine(cfg: &Engine) -> Result<Box<dyn OutputEngine>, String> {
match cfg.name.as_str() {
"stdout" => return Ok(Box::new(OutputEngineStdout{})),
"udp" => return build_output_engine_udp(&cfg),
_ => return Err("unknown output engine name".to_string() + &cfg.name),
}
}
struct OutputEngineStdout {}
impl OutputEngine for OutputEngineStdout {
fn put(&self, v: Vec<char>) {
println!("{}", v.iter().cloned().collect::<String>());
}
}
#[cfg(test)]
mod test_output {
use super::*;
struct OutputEngineTest {}
impl OutputEngine for OutputEngineTest {
fn put(&self, _v: Vec<char>) {
}
}
#[test]
fn test_output_engine_impl() {
let output_engine_test = OutputEngineTest{};
_test_output_engine_impl(&output_engine_test);
}
fn _test_output_engine_impl(engine: &dyn OutputEngine) {
engine.put("teehee".to_string().chars().collect());
}
}
struct OutputEngineUDP {
host: String,
port: i32,
}
pub fn build_output_engine_udp(cfg: &Engine) -> Result<Box<dyn OutputEngine>, String> {
let udp_cfg = cfg.udp.as_ref().unwrap();
return Ok(Box::new(OutputEngineUDP{
host: udp_cfg.host.clone().unwrap(),
port: udp_cfg.port,
}));
}
impl OutputEngine for OutputEngineUDP {
fn put(&self, v: Vec<char>) {
let socket = std::net::UdpSocket::bind("127.0.0.1:".to_string() + &(self.port+10).to_string()).unwrap();
socket.connect(self.host.to_string() + ":" + &self.port.to_string()).unwrap();
socket.send(&v.iter().cloned().collect::<String>().as_bytes()).unwrap();
}
}