use crate::actors::watcher_udev;
use crate::pipelines;
use crate::pipelines::{PIPELINES, Builder, UnacquiredCamera, CameraInfo};
use std::io;
use std::sync::mpsc;
use std::thread;
#[derive(Debug, Clone)]
pub struct CreationKit {
pub info: CameraInfo,
pub builder: Builder,
}
pub type Cameras = Vec<CreationKit>;
#[derive(Debug)]
pub enum Message {
DeviceChange(watcher_udev::Event),
ShowCameras,
Stop,
}
impl From<watcher_udev::Event> for Message {
fn from(e: watcher_udev::Event) -> Self {
Message::DeviceChange(e)
}
}
pub struct Handle {
sender: mpsc::SyncSender<Message>,
thread: Option<thread::JoinHandle<Result<(), mpsc::RecvError>>>,
cam_receiver: mpsc::Receiver<Cameras>,
}
impl Handle {
pub fn stop(mut self)
-> Result<
Result<(), mpsc::RecvError>,
(Self, &'static str)
> {
match self.sender.send(Message::Stop) {
Ok(()) => Ok({
if let Some(thread) = self.thread.take() {
thread.join().unwrap()
} else {
Ok(())
}
}),
Err(_) => {
if self.thread.is_some()
&& self.thread.as_ref().map(|t| t.is_finished()).unwrap()
{
Ok(Ok(()))
} else {
Err((self, "Failed to contact thread"))
}
},
}
}
fn sender(&self) -> &mpsc::SyncSender<Message> {
&self.sender
}
pub fn cameras(&self) -> Cameras {
self.sender.send(Message::ShowCameras).unwrap();
self.cam_receiver.recv().unwrap()
}
pub fn create(&self, needed_id: &str)
-> Option<Result<UnacquiredCamera, pipelines::Error>>
{
self.cameras().into_iter()
.find(|CreationKit { info: CameraInfo { id, .. }, ..}| id == needed_id)
.map(|CreationKit { info, builder }| builder(info))
}
}
impl Drop for Handle {
fn drop(&mut self) {
let _ = self.sender.send(Message::Stop);
}
}
fn spawn_handle() -> Handle {
let (sender, receiver) = mpsc::sync_channel(1);
let (cam_sender, cam_receiver) = mpsc::sync_channel(1);
let thread = Some(thread::spawn(move || run(receiver, cam_sender)));
Handle { sender, thread, cam_receiver }
}
pub struct Tracker {
handle: Handle,
watcher: watcher_udev::Watcher,
}
use std::ops::Deref;
impl Deref for Tracker {
type Target = Handle;
fn deref(&self) -> &Self::Target {
&self.handle
}
}
impl Tracker {
pub fn stop(self) -> Result<(), ()> {
let _ = self.handle.stop().map_err(|_| ())?;
let _ = self.watcher.stop().map_err(|_| ())?;
Ok(())
}
}
pub fn spawn() -> Result<Tracker, io::Error> {
let cameras_list = spawn_handle();
let sender = cameras_list.sender().clone();
let watcher = watcher_udev::Watcher::spawn(
move |ev| {
let _ = sender.send(ev.into());
}
)?;
Ok(Tracker {
handle: cameras_list,
watcher,
})
}
fn run(
receiver: mpsc::Receiver<Message>,
sender: mpsc::SyncSender<Cameras>,
) -> Result<(), mpsc::RecvError> {
let mut cameras: Vec<CreationKit> = Vec::new();
let mut present_devices = Vec::new();
loop {
match receiver.recv()? {
Message::Stop => { break },
Message::DeviceChange(watcher_udev::Event {
kind: watcher_udev::EventKind::Added,
device,
}) => {
present_devices.push(device.clone());
let matching_cam = cameras.iter()
.find(|CreationKit { info, .. }| info.is_for_device(&device));
if let None = matching_cam {
if let Some(camera) = PIPELINES.iter().find_map(|check| check(&device)) {
cameras.push(camera);
}
}
},
Message::DeviceChange(watcher_udev::Event {
kind: watcher_udev::EventKind::Removed,
device,
}) => {
present_devices.iter()
.position(|d| *d == device)
.map(|i| present_devices.remove(i));
cameras.iter()
.position(|CreationKit { info, ..}| info.is_for_device(&device))
.map(|i| cameras.remove(i));
},
Message::ShowCameras => {
let _ = sender.send(
cameras.iter()
.map(|v| v.clone())
.collect()
);
},
}
}
Ok(())
}