candid_server 0.3.0

A server for reading and relaying messages on a CAN bus
Documentation
use std::sync::{mpsc, Arc, Mutex};
use std::thread;

use socketcan::{CANFrame, CANSocket};

/// Reads from the opened CAN socket and relays each frame to each stored client
pub struct CANReader {
    can_socket: Arc<Mutex<CANSocket>>,
    clients: Arc<Mutex<Vec<mpsc::Sender<CANFrame>>>>,
}

impl CANReader {
    /// Creates a new `CANReader` from the given socket. Spawns one thread for reading frames
    pub fn new(socket: CANSocket) -> (CANReader, thread::JoinHandle<()>) {
        let reader = CANReader {
            can_socket: Arc::new(Mutex::new(socket)),
            clients: Arc::new(Mutex::new(Vec::new())),
        };

        // Spawn thread for reader runtime
        let can_socket = Arc::clone(&reader.can_socket); // Thread takes ownership of these
        let clients = Arc::clone(&reader.clients);
        let handle = thread::spawn(move || {
            loop {
                // Read a frame from the socket.
                let frame = can_socket.lock().unwrap().read_frame().unwrap();

                // Write it to each client
                let mut dropped_clients = Vec::new();
                for (i, client) in clients.lock().unwrap().iter().enumerate() {
                    client.send(frame.clone()).unwrap_or_else(|_| {
                        // Indicate that this client's connection has been dropped
                        dropped_clients.push(i);
                    });
                }

                // Clean up dropped clients
                for i in dropped_clients {
                    clients.lock().unwrap().remove(i);
                }
            }
        });

        (reader, handle)
    }

    /// Registers a client with this `CANReader`
    pub fn add_client(&self, channel: mpsc::Sender<CANFrame>) {
        &self.clients.lock().unwrap().push(channel);
    }

    /// Returns a copy of the underlying `CANsocket`
    pub fn get_socket(&self) -> Arc<Mutex<CANSocket>> {
        Arc::clone(&self.can_socket)
    }
}