<commit_before>extern crate mio;
extern crate num;

use network::tcp::{TcpConnValue, TcpConn};
use event::{EventHandlerCommand, Event, EventHandlerCMD, EVENT_ON_CONNECTION_CLOSE, EVENT_ON_CONNECTION};
use std::sync::{Arc, RwLock};
use self::mio::channel::{Sender, Receiver, channel};
use self::mio::{Token, Poll, Ready, PollOpt, Events};
use self::num::{BigInt, Zero};
use std::process;
use std::collections::BTreeMap;
use std::io::{ErrorKind, Read};
use std::str::FromStr;

const RECEIVER_CHANNEL_TOKEN: Token = Token(1);
const READER_BUFFER_SIZE: usize = 65000;

pub enum TcpReaderCMD {
    HandleConnection,
    WriteDataToConn,
    WriteDataWithPath
}

pub struct TcpReaderCommand {
    pub cmd: TcpReaderCMD,
    pub conn_value: Vec<TcpConnValue>,
    pub conn: Vec<TcpConn>,
    pub data: Vec<Arc<Vec<u8>>>,
    pub socket_token: Vec<Token>,
    pub tokens: Vec<String>,
    pub event: Vec<Event>
}

pub struct TcpReader {
    connections: Arc<RwLock<Vec<TcpConnValue>>>,
    reader_conns: BTreeMap<Token, TcpConn>,

    // prime value for current node
    // we will use this for checking event trigger
    current_value: BigInt,

    // reader sender channels
    sender_channel: Sender<TcpReaderCommand>,
    receiver_channel: Receiver<TcpReaderCommand>,

    // channel for triggering events from networking
    event_handler_channel: Sender<EventHandlerCommand>,

    // Vector of channels for readers including current one
    pub reader_channels: Vec<Sender<TcpReaderCommand>>,
    pub reader_index: usize,

    // allocated buffer for batch reading from connection
    readable_buffer: Vec<u8>,

    poll: Poll,
    big_zero: BigInt
}

impl TcpReader {
    pub fn new(connections: Arc<RwLock<Vec<TcpConnValue>>>, event_handler: Sender<EventHandlerCommand>, value: BigInt) -> TcpReader {
        let (s, r) = channel::<TcpReaderCommand>();
        TcpReader {
            connections: connections,
            sender_channel: s,
            receiver_channel: r,
            reader_channels: vec![],
            reader_index: 0,
            poll: match Poll::new() {
                Ok(p) => p,
                Err(e) => {
                    warn!("Unable to create Poll service from TcpReader -> {}", e);
                    process::exit(1);
                }
            },
            big_zero: Zero::zero(),
            reader_conns: BTreeMap::new(),
            readable_buffer: vec![0; READER_BUFFER_SIZE],
            event_handler_channel: event_handler,
            current_value: value
        }
    }

    pub fn channel(&self) -> Sender<TcpReaderCommand> {
        self.sender_channel.clone()
    }

    pub fn run(&mut self) {
        match self.poll.register(&self.receiver_channel, RECEIVER_CHANNEL_TOKEN, Ready::readable(), PollOpt::edge()) {
            Ok(_) => {},
            Err(e) => {
                warn!("Unable to register receiver channel to Poll service for Reader -> {}", e);
                return;
            }
        }

        // making events for handling 5K events at once
        let mut events: Events = Events::with_capacity(50000);
        loop {
            let event_count = self.poll.poll(&mut events, None).unwrap();
            if event_count == 0 {
                continue;
            }

            for event in events.into_iter() {
                let token = event.token();
                if token == RECEIVER_CHANNEL_TOKEN {
                    // trying to get commands while there is available data
                    loop {
                        match self.receiver_channel.try_recv() {
                            Ok(cmd) => {
                                let mut c = cmd;
                                self.notify(&mut c);
                            }
                            // if we got error, then data is unavailable
                            // and breaking receive loop
                            Err(_) => break
                        }
                    }
                    continue;
                }

                let kind = event.kind();

                if kind.is_error() || kind.is_hup() {
                    // if this error on connection, then we need to close it
                    self.close_connection(token);
                    continue;
                }

                if kind.is_readable() {
                    self.readable(token);
                    continue;
                }

                if kind.is_writable() {
                    self.writable(token);
                    continue;
                }
            }
        }
    }

    #[inline(always)]
    fn notify(&mut self, command: &mut TcpReaderCommand) {
        match command.cmd {
            TcpReaderCMD::HandleConnection => {
                let conn = match command.conn.pop() {
                    Some(c) => c,
                    None => return
                };

                let conn_value = match command.conn_value.pop() {
                    Some(c) => c,
                    None => return
                };

                // keeping this for event trigger
                let conn_value_token = conn_value.token.clone();
                match self.poll.register(&conn.socket_r, conn.socket_token, Ready::writable(), PollOpt::edge()) {
                    Ok(_) => {},
                    Err(e) => {
                        warn!("Unable to register connection from reader, closing it -> {}", e);
                        return;
                    }
                }

                // locking connections as writable for inserting received connection
                {
                    let mut conns_v = match self.connections.write() {
                        Ok(c) => c,
                        Err(e) => {
                            warn!("Unable to set writable lock for global connections list -> {}", e);
                            return;
                        }
                    };

                    conns_v.push(conn_value);
                }

                // inserting connection to the list of current reader
                self.reader_conns.insert(conn.socket_token, conn);

                let mut ev = Event::default();
                ev.name = String::from(EVENT_ON_CONNECTION);
                ev.from = conn_value_token;

                // triggering event about new accepted connection
                let _ = self.event_handler_channel.send(EventHandlerCommand {
                    cmd: EventHandlerCMD::TriggerFromEvent,
                    event: Arc::new(ev)
                });
            }

            TcpReaderCMD::WriteDataToConn => {
                // extracting data from command
                let send_data = match command.data.pop() {
                    Some(d) => d,
                    None => return
                };

                for i in 0..command.socket_token.len() {
                    match self.reader_conns.get_mut(&command.socket_token[i]) {
                        Some(conn) => {
                            // saving data to connection write queue for sending it
                            conn.add_writable_data(send_data.clone());

                            // reregistering connection as writable
                            match self.poll.reregister(&conn.socket_r, conn.socket_token, Ready::writable(), PollOpt::edge()) {
                                Ok(_) => {},
                                Err(e) => {
                                    warn!("Unable to reregister connection as writable for reader poll, from write data command functionality -> {}", e);
                                    continue;
                                }
                            };
                        }
                        None => continue
                    }
                }
            }

            TcpReaderCMD::WriteDataWithPath => {
                let mut ev = match command.event.pop() {
                    Some(e) => e,
                    None => return
                };

                let mut path = match BigInt::from_str(ev.path.as_str()) {
                    Ok(p) => p,
                    Err(e) => {
                        warn!("Unable to convert path from event, to BigInt for handline Write By path command -> {}", e);
                        return;
                    }
                };

                let mut need_to_trigger = false;
                // if event path is dividable to current node value
                // then we need to trigger event
                if self.current_value != self.big_zero && path.clone() % self.current_value.clone() == self.big_zero {
                    path = path.clone() / self.current_value.clone();
                    need_to_trigger = true;
                }

                if path != self.big_zero {
                    self.write_by_path(path, &mut ev);
                }

                if need_to_trigger {
                    let _ = self.event_handler_channel.send(EventHandlerCommand {
                        cmd: EventHandlerCMD::TriggerFromEvent,
                        event: Arc::new(ev)
                    });
                }
            }
        }
    }

    #[inline(always)]
    fn readable(&mut self, token: Token) {
        let mut close_conn = false;
        let mut final_data: Vec<Vec<u8>> = vec![];
        {
            let mut conn = match self.reader_conns.get_mut(&token) {
                Some(c) => c,
                None => return
            };

            loop {
                if close_conn {
                    break
                }

                match conn.socket_r.read(&mut self.readable_buffer) {
                    Ok(rsize) => {
                        // we got EOF or not
                        if rsize == 0 {
                            close_conn = true;
                            break;
                        } else {
                            let (r_data, keep_connection) = conn.handle_data(&mut self.readable_buffer, rsize);
                            if keep_connection {
                                final_data = r_data;
                            } else {
                                close_conn = true;
                                break;
                            }
                        }

                        // if we got data less than our buffer then we got all pending data
                        // from socket buffer
                        if rsize < self.readable_buffer.len() {
                            break
                        }
                    }
                    Err(e) => {
                        // if we got WouldBlock, then this is Non Blocking socket
                        // and data still not available for this, so it's not a connection error
                        if e.kind() == ErrorKind::WouldBlock {
                            return;
                        }

                        close_conn = true;
                        break;
                    }
                }
            }
        }

        if close_conn {
            self.close_connection(token);
            return;
        }

        // if we got here then we don't need to close connection
        // so parsing data which came from socket
        loop {
            self.handle_event_data(match final_data.pop() {
                Some(d) => d,
                None => break
            })
        }
    }

    #[inline(always)]
    fn writable(&mut self, token: Token) {
        let mut close_conn = false;

        {
            let mut conn = match self.reader_conns.get_mut(&token) {
                Some(c) => c,
                None => return
            };

            match conn.flush_write_queue() {
                Ok(end_of_q) => {
                    let mut ready_state = Ready::readable();

                    // if we don't have data in our connection Queue
                    // then we need to reregister connection only for reading
                    if !end_of_q {
                        ready_state = Ready::writable();
                    }

                    match self.poll.reregister(&conn.socket_r, conn.socket_token, ready_state, PollOpt::edge()) {
                        Ok(_) => {},
                        Err(e) => {
                            warn!("Unable to reregister connection for reader poll, from writable functionality -> {}", e);
                            return;
                        }
                    }
                }
                Err(_) => close_conn = true
            }
        }

        if close_conn {
            self.close_connection(token);
        }
    }

    #[inline(always)]
    fn close_connection(&mut self, token: Token) {
        let conn = match self.reader_conns.remove(&token) {
            Some(c) => c,
            None => return
        };

        let mut conn_index: i32 = -1;
        // trying to find connection based on token from conn
        {
            let conns_v = match self.connections.read() {
                Ok(c) => c,
                Err(e) => {
                    warn!("Unable to set readable lock for global connections list -> {}", e);
                    return;
                }
            };

            for i in 0..conns_v.len() {
                if conns_v[i].socket_token == conn.socket_token {
                    conn_index = i as i32;
                    break;
                }
            }
        }

        // we could't find connection index
        // so we need just to return
        if conn_index < 0 {
            return;
        }

        let mut ev = Event::default();
        ev.name = String::from(EVENT_ON_CONNECTION_CLOSE);

        // if we have a connection index
        // now just locking for write and deleting specific index
        {
            let mut conns_v = match self.connections.write() {
                Ok(c) => c,
                Err(e) => {
                    warn!("Unable to set writable lock for global connections list -> {}", e);
                    return;
                }
            };

            // deleting connection here
            ev.from = conns_v.remove(conn_index as usize).token;
        }

        let _ = self.event_handler_channel.send(EventHandlerCommand {
            cmd: EventHandlerCMD::TriggerFromEvent,
            event: Arc::new(ev)
        });
    }

    #[inline(always)]
    fn handle_event_data(&mut self, buffer: Vec<u8>) {
        let mut ev = match Event::from_raw(buffer.as_ref()) {
            Ok(e) => e,
            Err(e) => {
                warn!("Error while trying to convert raw data to event object -> {}", e);
                Event{
                    path: String::new(),
                    name: String::new(),
                    from: String::new(),
                    target: String::new(),
                    public_data: String::new(),
                    data: vec![],
                }
            }
        };

        let mut path = Zero::zero();

        if !ev.path.is_empty() {
            path = match BigInt::from_str(ev.path.as_str()) {
                Ok(p) => p,
                Err(e) => {
                    warn!("Error while trying to convert parsed Event Path to BigInt path -> {}", e);
                    return;
                }
            };
        }

        // if path is 0
        // we don't need to check path combination
        if path != self.big_zero {
            self.write_by_path(path, &mut ev);
        }

        if !ev.name.is_empty() {
            let _ = self.event_handler_channel.send(EventHandlerCommand {
                cmd: EventHandlerCMD::TriggerFromEvent,
                event: Arc::new(ev)
            });
        }
    }

    fn write_by_path(&self, send_path: BigInt, ev: &mut Event) {
        let readers_len = self.reader_channels.len();
        // we will save connection token and reader index
        let mut conn_tokens: Vec<Vec<Token>> = vec![];
        for _ in 0..readers_len {
            conn_tokens.push(vec![]);
        }

        let mut path = send_path;
        // locking connections as readable for checking
        // path information from parsed event
        {
            let conns_v = match self.connections.read() {
                Ok(c) => c,
                Err(e) => {
                    warn!("Unable to set readable lock for global connections list -> {}", e);
                    return;
                }
            };

            for c in conns_v.iter() {
                if c.value == self.big_zero {
                    continue
                }

                // if connection is dividable to path then keeping divided path
                // and saving connection token for later writing to that connection
                if path.clone() % c.value.clone() == self.big_zero {
                    path = path.clone() / c.value.clone();
                    conn_tokens[c.reader_index].push(c.socket_token);
                }
            }
        }

        // setting final path
        ev.path = path.to_str_radix(10);
        let send_data = Arc::new(match ev.to_raw() {
            Ok(d) => d,
            Err(e) => {
                warn!("Unable to parse event to data with final path -> {}", e);
                return;
            }
        });

        for i in 0..readers_len {
            if conn_tokens.len() == 0 {
                break;
            }

            let tokens = conn_tokens.remove(0);
            if tokens.len() == 0 {
                continue;
            }

            // sending async command to write data for this connection
            let _ = self.reader_channels[i].send(TcpReaderCommand {
                cmd: TcpReaderCMD::WriteDataToConn,
                conn_value: vec![],
                conn: vec![],
                data: vec![send_data.clone()],
                socket_token: tokens,
                tokens: vec![],
                event: vec![]
            });
        }
    }
}
<commit_msg>fixed data handler<commit_after>extern crate mio;
extern crate num;

use network::tcp::{TcpConnValue, TcpConn};
use event::{EventHandlerCommand, Event, EventHandlerCMD, EVENT_ON_CONNECTION_CLOSE, EVENT_ON_CONNECTION};
use std::sync::{Arc, RwLock};
use self::mio::channel::{Sender, Receiver, channel};
use self::mio::{Token, Poll, Ready, PollOpt, Events};
use self::num::{BigInt, Zero};
use std::process;
use std::collections::BTreeMap;
use std::io::{ErrorKind, Read};
use std::str::FromStr;

const RECEIVER_CHANNEL_TOKEN: Token = Token(1);
const READER_BUFFER_SIZE: usize = 65000;

pub enum TcpReaderCMD {
    HandleConnection,
    WriteDataToConn,
    WriteDataWithPath
}

pub struct TcpReaderCommand {
    pub cmd: TcpReaderCMD,
    pub conn_value: Vec<TcpConnValue>,
    pub conn: Vec<TcpConn>,
    pub data: Vec<Arc<Vec<u8>>>,
    pub socket_token: Vec<Token>,
    pub tokens: Vec<String>,
    pub event: Vec<Event>
}

pub struct TcpReader {
    connections: Arc<RwLock<Vec<TcpConnValue>>>,
    reader_conns: BTreeMap<Token, TcpConn>,

    // prime value for current node
    // we will use this for checking event trigger
    current_value: BigInt,

    // reader sender channels
    sender_channel: Sender<TcpReaderCommand>,
    receiver_channel: Receiver<TcpReaderCommand>,

    // channel for triggering events from networking
    event_handler_channel: Sender<EventHandlerCommand>,

    // Vector of channels for readers including current one
    pub reader_channels: Vec<Sender<TcpReaderCommand>>,
    pub reader_index: usize,

    // allocated buffer for batch reading from connection
    readable_buffer: Vec<u8>,

    poll: Poll,
    big_zero: BigInt
}

impl TcpReader {
    pub fn new(connections: Arc<RwLock<Vec<TcpConnValue>>>, event_handler: Sender<EventHandlerCommand>, value: BigInt) -> TcpReader {
        let (s, r) = channel::<TcpReaderCommand>();
        TcpReader {
            connections: connections,
            sender_channel: s,
            receiver_channel: r,
            reader_channels: vec![],
            reader_index: 0,
            poll: match Poll::new() {
                Ok(p) => p,
                Err(e) => {
                    warn!("Unable to create Poll service from TcpReader -> {}", e);
                    process::exit(1);
                }
            },
            big_zero: Zero::zero(),
            reader_conns: BTreeMap::new(),
            readable_buffer: vec![0; READER_BUFFER_SIZE],
            event_handler_channel: event_handler,
            current_value: value
        }
    }

    pub fn channel(&self) -> Sender<TcpReaderCommand> {
        self.sender_channel.clone()
    }

    pub fn run(&mut self) {
        match self.poll.register(&self.receiver_channel, RECEIVER_CHANNEL_TOKEN, Ready::readable(), PollOpt::edge()) {
            Ok(_) => {},
            Err(e) => {
                warn!("Unable to register receiver channel to Poll service for Reader -> {}", e);
                return;
            }
        }

        // making events for handling 5K events at once
        let mut events: Events = Events::with_capacity(50000);
        loop {
            let event_count = self.poll.poll(&mut events, None).unwrap();
            if event_count == 0 {
                continue;
            }

            for event in events.into_iter() {
                let token = event.token();
                if token == RECEIVER_CHANNEL_TOKEN {
                    // trying to get commands while there is available data
                    loop {
                        match self.receiver_channel.try_recv() {
                            Ok(cmd) => {
                                let mut c = cmd;
                                self.notify(&mut c);
                            }
                            // if we got error, then data is unavailable
                            // and breaking receive loop
                            Err(_) => break
                        }
                    }
                    continue;
                }

                let kind = event.kind();

                if kind.is_error() || kind.is_hup() {
                    // if this error on connection, then we need to close it
                    self.close_connection(token);
                    continue;
                }

                if kind.is_readable() {
                    self.readable(token);
                    continue;
                }

                if kind.is_writable() {
                    self.writable(token);
                    continue;
                }
            }
        }
    }

    #[inline(always)]
    fn notify(&mut self, command: &mut TcpReaderCommand) {
        match command.cmd {
            TcpReaderCMD::HandleConnection => {
                let conn = match command.conn.pop() {
                    Some(c) => c,
                    None => return
                };

                let conn_value = match command.conn_value.pop() {
                    Some(c) => c,
                    None => return
                };

                // keeping this for event trigger
                let conn_value_token = conn_value.token.clone();
                match self.poll.register(&conn.socket_r, conn.socket_token, Ready::writable(), PollOpt::edge()) {
                    Ok(_) => {},
                    Err(e) => {
                        warn!("Unable to register connection from reader, closing it -> {}", e);
                        return;
                    }
                }

                // locking connections as writable for inserting received connection
                {
                    let mut conns_v = match self.connections.write() {
                        Ok(c) => c,
                        Err(e) => {
                            warn!("Unable to set writable lock for global connections list -> {}", e);
                            return;
                        }
                    };

                    conns_v.push(conn_value);
                }

                // inserting connection to the list of current reader
                self.reader_conns.insert(conn.socket_token, conn);

                let mut ev = Event::default();
                ev.name = String::from(EVENT_ON_CONNECTION);
                ev.from = conn_value_token;

                // triggering event about new accepted connection
                let _ = self.event_handler_channel.send(EventHandlerCommand {
                    cmd: EventHandlerCMD::TriggerFromEvent,
                    event: Arc::new(ev)
                });
            }

            TcpReaderCMD::WriteDataToConn => {
                // extracting data from command
                let send_data = match command.data.pop() {
                    Some(d) => d,
                    None => return
                };

                for i in 0..command.socket_token.len() {
                    match self.reader_conns.get_mut(&command.socket_token[i]) {
                        Some(conn) => {
                            // saving data to connection write queue for sending it
                            conn.add_writable_data(send_data.clone());

                            // reregistering connection as writable
                            match self.poll.reregister(&conn.socket_r, conn.socket_token, Ready::writable(), PollOpt::edge()) {
                                Ok(_) => {},
                                Err(e) => {
                                    warn!("Unable to reregister connection as writable for reader poll, from write data command functionality -> {}", e);
                                    continue;
                                }
                            };
                        }
                        None => continue
                    }
                }
            }

            TcpReaderCMD::WriteDataWithPath => {
                let mut ev = match command.event.pop() {
                    Some(e) => e,
                    None => return
                };

                let mut path = match BigInt::from_str(ev.path.as_str()) {
                    Ok(p) => p,
                    Err(e) => {
                        warn!("Unable to convert path from event, to BigInt for handline Write By path command -> {}", e);
                        return;
                    }
                };

                let mut need_to_trigger = false;
                // if event path is dividable to current node value
                // then we need to trigger event
                if self.current_value != self.big_zero && path.clone() % self.current_value.clone() == self.big_zero {
                    path = path.clone() / self.current_value.clone();
                    need_to_trigger = true;
                }

                if path != self.big_zero {
                    self.write_by_path(path, &mut ev);
                }

                if need_to_trigger {
                    let _ = self.event_handler_channel.send(EventHandlerCommand {
                        cmd: EventHandlerCMD::TriggerFromEvent,
                        event: Arc::new(ev)
                    });
                }
            }
        }
    }

    #[inline(always)]
    fn readable(&mut self, token: Token) {
        let mut close_conn = false;
        let mut final_data: Vec<Vec<u8>> = vec![];
        {
            let mut conn = match self.reader_conns.get_mut(&token) {
                Some(c) => c,
                None => return
            };

            loop {
                if close_conn {
                    break
                }

                match conn.socket_r.read(&mut self.readable_buffer) {
                    Ok(rsize) => {
                        // we got EOF or not
                        if rsize == 0 {
                            close_conn = true;
                            break;
                        } else {
                            let (r_data, keep_connection) = conn.handle_data(&mut self.readable_buffer, rsize);
                            if keep_connection {
                                final_data = r_data;
                            } else {
                                close_conn = true;
                                break;
                            }
                        }

                        // if we got data less than our buffer then we got all pending data
                        // from socket buffer
                        if rsize < self.readable_buffer.len() {
                            break
                        }
                    }
                    Err(e) => {
                        // if we got WouldBlock, then this is Non Blocking socket
                        // and data still not available for this, so it's not a connection error
                        if e.kind() == ErrorKind::WouldBlock {
                            return;
                        }

                        close_conn = true;
                        break;
                    }
                }
            }
        }

        // in any case need to handle data if we received something
        // so parsing data which came from socket
        loop {
            self.handle_event_data(match final_data.pop() {
                Some(d) => d,
                None => break
            })
        }

        if close_conn {
            self.close_connection(token);
            return;
        }
    }

    #[inline(always)]
    fn writable(&mut self, token: Token) {
        let mut close_conn = false;

        {
            let mut conn = match self.reader_conns.get_mut(&token) {
                Some(c) => c,
                None => return
            };

            match conn.flush_write_queue() {
                Ok(end_of_q) => {
                    let mut ready_state = Ready::readable();

                    // if we don't have data in our connection Queue
                    // then we need to reregister connection only for reading
                    if !end_of_q {
                        ready_state = Ready::writable();
                    }

                    match self.poll.reregister(&conn.socket_r, conn.socket_token, ready_state, PollOpt::edge()) {
                        Ok(_) => {},
                        Err(e) => {
                            warn!("Unable to reregister connection for reader poll, from writable functionality -> {}", e);
                            return;
                        }
                    }
                }
                Err(_) => close_conn = true
            }
        }

        if close_conn {
            self.close_connection(token);
        }
    }

    #[inline(always)]
    fn close_connection(&mut self, token: Token) {
        let conn = match self.reader_conns.remove(&token) {
            Some(c) => c,
            None => return
        };

        let mut conn_index: i32 = -1;
        // trying to find connection based on token from conn
        {
            let conns_v = match self.connections.read() {
                Ok(c) => c,
                Err(e) => {
                    warn!("Unable to set readable lock for global connections list -> {}", e);
                    return;
                }
            };

            for i in 0..conns_v.len() {
                if conns_v[i].socket_token == conn.socket_token {
                    conn_index = i as i32;
                    break;
                }
            }
        }

        // we could't find connection index
        // so we need just to return
        if conn_index < 0 {
            return;
        }

        let mut ev = Event::default();
        ev.name = String::from(EVENT_ON_CONNECTION_CLOSE);

        // if we have a connection index
        // now just locking for write and deleting specific index
        {
            let mut conns_v = match self.connections.write() {
                Ok(c) => c,
                Err(e) => {
                    warn!("Unable to set writable lock for global connections list -> {}", e);
                    return;
                }
            };

            // deleting connection here
            ev.from = conns_v.remove(conn_index as usize).token;
        }

        let _ = self.event_handler_channel.send(EventHandlerCommand {
            cmd: EventHandlerCMD::TriggerFromEvent,
            event: Arc::new(ev)
        });
    }

    #[inline(always)]
    fn handle_event_data(&mut self, buffer: Vec<u8>) {
        let mut ev = match Event::from_raw(buffer.as_ref()) {
            Ok(e) => e,
            Err(e) => {
                warn!("Error while trying to convert raw data to event object -> {}", e);
                Event{
                    path: String::new(),
                    name: String::new(),
                    from: String::new(),
                    target: String::new(),
                    public_data: String::new(),
                    data: vec![],
                }
            }
        };

        let mut path = Zero::zero();

        if !ev.path.is_empty() {
            path = match BigInt::from_str(ev.path.as_str()) {
                Ok(p) => p,
                Err(e) => {
                    warn!("Error while trying to convert parsed Event Path to BigInt path -> {}", e);
                    return;
                }
            };
        }

        // if path is 0
        // we don't need to check path combination
        if path != self.big_zero {
            self.write_by_path(path, &mut ev);
        }

        if !ev.name.is_empty() {
            let _ = self.event_handler_channel.send(EventHandlerCommand {
                cmd: EventHandlerCMD::TriggerFromEvent,
                event: Arc::new(ev)
            });
        }
    }

    fn write_by_path(&self, send_path: BigInt, ev: &mut Event) {
        let readers_len = self.reader_channels.len();
        // we will save connection token and reader index
        let mut conn_tokens: Vec<Vec<Token>> = vec![];
        for _ in 0..readers_len {
            conn_tokens.push(vec![]);
        }

        let mut path = send_path;
        // locking connections as readable for checking
        // path information from parsed event
        {
            let conns_v = match self.connections.read() {
                Ok(c) => c,
                Err(e) => {
                    warn!("Unable to set readable lock for global connections list -> {}", e);
                    return;
                }
            };

            for c in conns_v.iter() {
                if c.value == self.big_zero {
                    continue
                }

                // if connection is dividable to path then keeping divided path
                // and saving connection token for later writing to that connection
                if path.clone() % c.value.clone() == self.big_zero {
                    path = path.clone() / c.value.clone();
                    conn_tokens[c.reader_index].push(c.socket_token);
                }
            }
        }

        // setting final path
        ev.path = path.to_str_radix(10);
        let send_data = Arc::new(match ev.to_raw() {
            Ok(d) => d,
            Err(e) => {
                warn!("Unable to parse event to data with final path -> {}", e);
                return;
            }
        });

        for i in 0..readers_len {
            if conn_tokens.len() == 0 {
                break;
            }

            let tokens = conn_tokens.remove(0);
            if tokens.len() == 0 {
                continue;
            }

            // sending async command to write data for this connection
            let _ = self.reader_channels[i].send(TcpReaderCommand {
                cmd: TcpReaderCMD::WriteDataToConn,
                conn_value: vec![],
                conn: vec![],
                data: vec![send_data.clone()],
                socket_token: tokens,
                tokens: vec![],
                event: vec![]
            });
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "zstd")]
use zstd::block::{compress, decompress};

use crate::*;

use super::{
    arr_to_u32, gc_blobs, pwrite_all, raw_segment_iter_from, u32_to_arr,
    u64_to_arr, BasedBuf, DiskPtr, LogIter, LogKind, LogOffset, Lsn,
    MessageKind,
};

/// A snapshot of the state required to quickly restart
/// the `PageCache` and `SegmentAccountant`.
#[derive(Debug, Default)]
#[cfg_attr(test, derive(Clone, PartialEq))]
pub struct Snapshot {
    /// The last read message lsn
    pub stable_lsn: Lsn,
    /// The last read message lid
    pub tip_lid: Option<LogOffset>,
    /// the mapping from pages to (lsn, lid)
    pub pt: Vec<PageState>,
}

#[derive(Clone, Debug, PartialEq)]
pub enum PageState {
    Present { base: (Lsn, DiskPtr, u64), frags: Vec<(Lsn, DiskPtr, u64)> },
    Free(Lsn, DiskPtr),
    Uninitialized,
}

impl PageState {
    fn push(&mut self, item: (Lsn, DiskPtr, u64)) {
        match *self {
            PageState::Present { base, ref mut frags } => {
                if frags.last().map_or(base.0, |f| f.0) < item.0 {
                    frags.push(item)
                } else {
                    debug!(
                        "skipping merging item {:?} into \
                        existing PageState::Present({:?})",
                        item, frags
                    );
                }
            }
            _ => panic!("pushed frags to {:?}", self),
        }
    }

    pub(crate) fn is_free(&self) -> bool {
        match *self {
            PageState::Free(_, _) => true,
            _ => false,
        }
    }
}

impl Snapshot {
    fn apply(
        &mut self,
        log_kind: LogKind,
        pid: PageId,
        lsn: Lsn,
        disk_ptr: DiskPtr,
        sz: u64,
    ) {
        trace!("trying to deserialize buf for ptr {} lsn {}", disk_ptr, lsn);
        let _measure = Measure::new(&M.snapshot_apply);

        let pushed = if self.pt.len() <= usize::try_from(pid).unwrap() {
            self.pt.resize(
                usize::try_from(pid + 1).unwrap(),
                PageState::Uninitialized,
            );
            true
        } else {
            false
        };

        match log_kind {
            LogKind::Replace => {
                trace!(
                    "compact of pid {} at ptr {} lsn {}",
                    pid,
                    disk_ptr,
                    lsn,
                );

                self.pt[usize::try_from(pid).unwrap()] = PageState::Present {
                    base: (lsn, disk_ptr, sz),
                    frags: vec![],
                };
            }
            LogKind::Link => {
                // Because we rewrite pages over time, we may have relocated
                // a page's initial Compact to a later segment. We should skip
                // over pages here unless we've encountered a Compact for them.
                if let Some(lids @ PageState::Present { .. }) =
                    self.pt.get_mut(usize::try_from(pid).unwrap())
                {
                    trace!(
                        "append of pid {} at lid {} lsn {}",
                        pid,
                        disk_ptr,
                        lsn,
                    );

                    if lids.is_free() {
                        // this can happen if the allocate or replace
                        // has been moved to a later segment.

                        trace!(
                            "we have not yet encountered an \
                             allocation of this page, skipping push"
                        );

                        return;
                    }

                    lids.push((lsn, disk_ptr, sz));
                } else {
                    trace!(
                        "skipping dangling append of pid {} at lid {} lsn {}",
                        pid,
                        disk_ptr,
                        lsn,
                    );
                    if pushed {
                        let old = self.pt.pop().unwrap();
                        assert_eq!(old, PageState::Uninitialized);
                    }
                }
            }
            LogKind::Free => {
                trace!("free of pid {} at ptr {} lsn {}", pid, disk_ptr, lsn);
                self.pt[usize::try_from(pid).unwrap()] =
                    PageState::Free(lsn, disk_ptr);
            }
            LogKind::Corrupted | LogKind::Skip => panic!(
                "unexppected messagekind in snapshot application: {:?}",
                log_kind
            ),
        }
    }
}

fn advance_snapshot(
    mut iter: LogIter,
    mut snapshot: Snapshot,
    config: &RunningConfig,
) -> Result<Snapshot> {
    let _measure = Measure::new(&M.advance_snapshot);

    trace!("building on top of old snapshot: {:?}", snapshot);

    let old_stable_lsn = snapshot.stable_lsn;

    while let Some((log_kind, pid, lsn, ptr, sz)) = iter.next() {
        trace!(
            "in advance_snapshot looking at item with pid {} lsn {} ptr {}",
            pid,
            lsn,
            ptr
        );

        if lsn < snapshot.stable_lsn {
            // don't process already-processed Lsn's. stable_lsn is for the last
            // item ALREADY INCLUDED lsn in the snapshot.
            trace!(
                "continuing in advance_snapshot, lsn {} ptr {} stable_lsn {:?}",
                lsn,
                ptr,
                snapshot.stable_lsn
            );
            continue;
        }

        snapshot.apply(log_kind, pid, lsn, ptr, sz);
    }

    // `snapshot.tip_lid` can be set based on 4 possibilities for the tip of the
    // log:
    // 1. an empty DB - tip set to None, causing a fresh segment to be
    //    allocated on initialization
    // 2. the recovered tip is at the end of a
    //    segment with less space left than would fit MAX_MSG_HEADER_LEN -
    //    tip set to None, causing a fresh segment to be allocated on
    //    initialization, as in #1 above
    // 3. the recovered tip is in the middle of a segment - both set to the end
    //    of the last valid message, causing the system to be initialized to
    //    that point without allocating a new segment
    // 4. the recovered tip is at the beginning of a new segment, but without
    //    any valid messages in it yet. treat as #3 above, but also take care
    //    in te SA initialization to properly initialize any segment tracking
    //    state despite not having any pages currently residing there.
    //
    // The information we have at this point is iter.cur_lsn and the
    // iter.segment_base.offset. Situation 1 & 2 happen if iter.cur_lsn %
    // segment_size == 0, and result in None for the recovered log tip.
    // Situations 3 & 4 otherwise. We don't need to differentiate between them
    // here.

    let segment_progress: Lsn = iter.cur_lsn % (config.segment_size as Lsn);

    snapshot.stable_lsn = if segment_progress + MAX_MSG_HEADER_LEN as Lsn
        >= config.segment_size as Lsn
    {
        assert!(iter.segment_base.is_none());
        config.normalize(iter.cur_lsn) + config.segment_size as Lsn
    } else if iter.cur_lsn == 0 {
        snapshot.stable_lsn
    } else {
        iter.cur_lsn
    };

    if segment_progress == 0 || iter.segment_base.is_none() {
        // either situation 1 or situation 2
        snapshot.tip_lid = None;
    } else if let Some(BasedBuf { offset, .. }) = iter.segment_base {
        // either situation 3 or situation 4. we need to zero the

        snapshot.tip_lid = Some(offset + segment_progress as LogOffset);

        // zero the tail of the segment after the recovered tip
        let shred_len = config.segment_size - segment_progress as usize;
        let shred_zone = vec![MessageKind::Corrupted.into(); shred_len];
        debug!(
            "zeroing the end of the recovered segment between {} and {}",
            snapshot.tip_lid.unwrap(),
            snapshot.tip_lid.unwrap() + shred_len as LogOffset
        );
        pwrite_all(&config.file, &shred_zone, snapshot.tip_lid.unwrap())?;
        config.file.sync_all()?;
    } else {
        unreachable!()
    }

    // turn off snapshot mutability
    let snapshot = snapshot;

    if snapshot.tip_lid.is_some() {
        assert!(segment_progress >= SEG_HEADER_LEN as Lsn);
    }

    trace!("generated snapshot: {:?}", snapshot);

    assert!(snapshot.stable_lsn >= old_stable_lsn);

    if snapshot.stable_lsn > old_stable_lsn {
        write_snapshot(config, &snapshot)?;
    }

    for to_zero in iter.segments.values().copied() {
        debug!("zeroing torn segment at lid {}", to_zero);

        // NB we intentionally corrupt this header to prevent any segment
        // from being allocated which would duplicate its LSN, messing
        // up recovery in the future.
        io_fail!(config, "segment initial free zero");
        pwrite_all(
            &config.file,
            &*vec![MessageKind::Corrupted.into(); config.segment_size],
            to_zero,
        )?;
        if !config.temporary {
            config.file.sync_all()?;
        }
    }

    // remove all blob files larger than our stable offset
    gc_blobs(config, snapshot.stable_lsn)?;

    #[cfg(feature = "event_log")]
    config.event_log.recovered_lsn(snapshot.stable_lsn);

    Ok(snapshot)
}

/// Read a `Snapshot` or generate a default, then advance it to
/// the tip of the data file, if present.
pub fn read_snapshot_or_default(config: &RunningConfig) -> Result<Snapshot> {
    let last_snap = read_snapshot(config)?.unwrap_or_else(Snapshot::default);

    let log_iter = raw_segment_iter_from(last_snap.stable_lsn, config)?;

    let res = advance_snapshot(log_iter, last_snap, config)?;

    Ok(res)
}

/// Read a `Snapshot` from disk.
fn read_snapshot(config: &RunningConfig) -> std::io::Result<Option<Snapshot>> {
    let mut f = loop {
        let mut candidates = config.get_snapshot_files()?;
        if candidates.is_empty() {
            debug!("no previous snapshot found");
            return Ok(None);
        }

        candidates.sort();

        let path = candidates.pop().unwrap();

        match std::fs::OpenOptions::new().read(true).open(&path) {
            Ok(f) => break f,
            Err(ref e) if e.kind() == std::io::ErrorKind::NotFound => {
                // this can happen if there's a race
                continue;
            }
            Err(other) => return Err(other),
        }
    };

    let mut buf = vec![];
    let _read = f.read_to_end(&mut buf)?;
    let len = buf.len();
    if len <= 12 {
        warn!("empty/corrupt snapshot file found");
        return Ok(None);
    }

    let mut len_expected_bytes = [0; 8];
    len_expected_bytes.copy_from_slice(&buf[len - 12..len - 4]);

    let mut crc_expected_bytes = [0; 4];
    crc_expected_bytes.copy_from_slice(&buf[len - 4..]);

    let _ = buf.split_off(len - 12);
    let crc_expected: u32 = arr_to_u32(&crc_expected_bytes);

    let crc_actual = crc32(&buf);

    if crc_expected != crc_actual {
        return Ok(None);
    }

    #[cfg(feature = "zstd")]
    let bytes = if config.use_compression {
        use std::convert::TryInto;

        let len_expected: u64 =
            u64::from_le_bytes(len_expected_bytes.as_ref().try_into().unwrap());

        decompress(&*buf, usize::try_from(len_expected).unwrap()).unwrap()
    } else {
        buf
    };

    #[cfg(not(feature = "zstd"))]
    let bytes = buf;

    Ok(Snapshot::deserialize(&mut bytes.as_slice()).ok())
}

fn write_snapshot(config: &RunningConfig, snapshot: &Snapshot) -> Result<()> {
    trace!("writing snapshot {:?}", snapshot);

    let raw_bytes = snapshot.serialize();
    let decompressed_len = raw_bytes.len();

    #[cfg(feature = "zstd")]
    let bytes = if config.use_compression {
        compress(&*raw_bytes, config.compression_factor).unwrap()
    } else {
        raw_bytes
    };

    #[cfg(not(feature = "zstd"))]
    let bytes = raw_bytes;

    let crc32: [u8; 4] = u32_to_arr(crc32(&bytes));
    let len_bytes: [u8; 8] = u64_to_arr(decompressed_len as u64);

    let path_1_suffix = format!("snap.{:016X}.generating", snapshot.stable_lsn);

    let mut path_1 = config.get_path();
    path_1.push(path_1_suffix);

    let path_2_suffix = format!("snap.{:016X}", snapshot.stable_lsn);

    let mut path_2 = config.get_path();
    path_2.push(path_2_suffix);

    let parent = path_1.parent().unwrap();
    std::fs::create_dir_all(parent)?;
    let mut f =
        std::fs::OpenOptions::new().write(true).create(true).open(&path_1)?;

    // write the snapshot bytes, followed by a crc64 checksum at the end
    io_fail!(config, "snap write");
    f.write_all(&*bytes)?;
    io_fail!(config, "snap write len");
    f.write_all(&len_bytes)?;
    io_fail!(config, "snap write crc");
    f.write_all(&crc32)?;
    io_fail!(config, "snap write post");
    f.sync_all()?;

    trace!("wrote snapshot to {}", path_1.to_string_lossy());

    io_fail!(config, "snap write mv");
    std::fs::rename(&path_1, &path_2)?;
    io_fail!(config, "snap write mv post");

    trace!("renamed snapshot to {}", path_2.to_string_lossy());

    // clean up any old snapshots
    let candidates = config.get_snapshot_files()?;
    for path in candidates {
        let path_str = path.file_name().unwrap().to_str().unwrap();
        if !path_2.to_string_lossy().ends_with(&*path_str) {
            debug!("removing old snapshot file {:?}", path);

            io_fail!(config, "snap write rm old");

            if let Err(e) = std::fs::remove_file(&path) {
                // TODO should this just be a try return?
                warn!(
                    "failed to remove old snapshot file, maybe snapshot race? {}",
                    e
                );
            }
        }
    }
    Ok(())
}
<commit_msg>Refactor snapshot further to reduce error-proneness of recovery<commit_after>#[cfg(feature = "zstd")]
use zstd::block::{compress, decompress};

use crate::*;

use super::{
    arr_to_u32, gc_blobs, pwrite_all, raw_segment_iter_from, u32_to_arr,
    u64_to_arr, BasedBuf, DiskPtr, LogIter, LogKind, LogOffset, Lsn,
    MessageKind,
};

/// A snapshot of the state required to quickly restart
/// the `PageCache` and `SegmentAccountant`.
#[derive(PartialEq, Debug, Default)]
#[cfg_attr(test, derive(Clone, PartialEq))]
pub struct Snapshot {
    /// The last read message lsn
    pub stable_lsn: Option<Lsn>,
    /// The last read message lid
    pub active_segment: Option<LogOffset>,
    /// the mapping from pages to (lsn, lid)
    pub pt: Vec<PageState>,
}

#[derive(Clone, Debug, PartialEq)]
pub enum PageState {
    Present { base: (Lsn, DiskPtr, u64), frags: Vec<(Lsn, DiskPtr, u64)> },
    Free(Lsn, DiskPtr),
    Uninitialized,
}

impl PageState {
    fn push(&mut self, item: (Lsn, DiskPtr, u64)) {
        match *self {
            PageState::Present { base, ref mut frags } => {
                if frags.last().map_or(base.0, |f| f.0) < item.0 {
                    frags.push(item)
                } else {
                    debug!(
                        "skipping merging item {:?} into \
                        existing PageState::Present({:?})",
                        item, frags
                    );
                }
            }
            _ => panic!("pushed frags to {:?}", self),
        }
    }

    pub(crate) fn is_free(&self) -> bool {
        match *self {
            PageState::Free(_, _) => true,
            _ => false,
        }
    }
}

impl Snapshot {
    fn apply(
        &mut self,
        log_kind: LogKind,
        pid: PageId,
        lsn: Lsn,
        disk_ptr: DiskPtr,
        sz: u64,
    ) {
        trace!("trying to deserialize buf for ptr {} lsn {}", disk_ptr, lsn);
        let _measure = Measure::new(&M.snapshot_apply);

        let pushed = if self.pt.len() <= usize::try_from(pid).unwrap() {
            self.pt.resize(
                usize::try_from(pid + 1).unwrap(),
                PageState::Uninitialized,
            );
            true
        } else {
            false
        };

        match log_kind {
            LogKind::Replace => {
                trace!(
                    "compact of pid {} at ptr {} lsn {}",
                    pid,
                    disk_ptr,
                    lsn,
                );

                self.pt[usize::try_from(pid).unwrap()] = PageState::Present {
                    base: (lsn, disk_ptr, sz),
                    frags: vec![],
                };
            }
            LogKind::Link => {
                // Because we rewrite pages over time, we may have relocated
                // a page's initial Compact to a later segment. We should skip
                // over pages here unless we've encountered a Compact for them.
                if let Some(lids @ PageState::Present { .. }) =
                    self.pt.get_mut(usize::try_from(pid).unwrap())
                {
                    trace!(
                        "append of pid {} at lid {} lsn {}",
                        pid,
                        disk_ptr,
                        lsn,
                    );

                    lids.push((lsn, disk_ptr, sz));
                } else {
                    trace!(
                        "skipping dangling append of pid {} at lid {} lsn {}",
                        pid,
                        disk_ptr,
                        lsn,
                    );
                    if pushed {
                        let old = self.pt.pop().unwrap();
                        assert_eq!(old, PageState::Uninitialized);
                    }
                }
            }
            LogKind::Free => {
                trace!("free of pid {} at ptr {} lsn {}", pid, disk_ptr, lsn);
                self.pt[usize::try_from(pid).unwrap()] =
                    PageState::Free(lsn, disk_ptr);
            }
            LogKind::Corrupted | LogKind::Skip => panic!(
                "unexppected messagekind in snapshot application: {:?}",
                log_kind
            ),
        }
    }
}

fn advance_snapshot(
    mut iter: LogIter,
    mut snapshot: Snapshot,
    config: &RunningConfig,
) -> Result<Snapshot> {
    let _measure = Measure::new(&M.advance_snapshot);

    trace!("building on top of old snapshot: {:?}", snapshot);

    let old_stable_lsn = snapshot.stable_lsn;

    while let Some((log_kind, pid, lsn, ptr, sz)) = iter.next() {
        trace!(
            "in advance_snapshot looking at item with pid {} lsn {} ptr {}",
            pid,
            lsn,
            ptr
        );

        if lsn < snapshot.stable_lsn {
            // don't process already-processed Lsn's. stable_lsn is for the last
            // item ALREADY INCLUDED lsn in the snapshot.
            trace!(
                "continuing in advance_snapshot, lsn {} ptr {} stable_lsn {:?}",
                lsn,
                ptr,
                snapshot.stable_lsn
            );
            continue;
        }

        snapshot.apply(log_kind, pid, lsn, ptr, sz);
    }

    // `snapshot.tip_lid` can be set based on 4 possibilities for the tip of the
    // log:
    // 1. an empty DB - tip set to None, causing a fresh segment to be
    //    allocated on initialization
    // 2. the recovered tip is at the end of a
    //    segment with less space left than would fit MAX_MSG_HEADER_LEN -
    //    tip set to None, causing a fresh segment to be allocated on
    //    initialization, as in #1 above
    // 3. the recovered tip is in the middle of a segment - both set to the end
    //    of the last valid message, causing the system to be initialized to
    //    that point without allocating a new segment
    // 4. the recovered tip is at the beginning of a new segment, but without
    //    any valid messages in it yet. treat as #3 above, but also take care
    //    in te SA initialization to properly initialize any segment tracking
    //    state despite not having any pages currently residing there.
    //
    // The information we have at this point is iter.cur_lsn and the
    // iter.segment_base.offset. Situation 1 & 2 happen if iter.cur_lsn %
    // segment_size == 0, and result in None for the recovered log tip.
    // Situations 3 & 4 otherwise. We don't need to differentiate between them
    // here.

    // we need to put 2 things into the snapshot:
    // 1. stable_lsn:
    //  if db is empty:
    //      None
    //  else:
    //      max(last stable_lsn, SEG_HEADER_LEN, iter.cur_lsn)
    // 2. active_segment:
    //  if db is empty:
    //      None
    //  else if progress is
    let nothing_happened = iter.cur_lsn == 0;
    let db_is_empty = nothing_happened && snapshot.stable_lsn.is_none();

    let snapshot = if db_is_empty {
        trace!("db is empty, returning default snapshot");
        assert_eq!(snapshot, Snapshot::default());
        snapshot
    } else if nothing_happened {
        trace!(
            "nothing happened since the last snapshot \
            was generated, returning the previous one"
        );
        snapshot
    } else {
        let iterated_lsn = iter.cur_lsn;
        drop(iter);
        assert!(iterated_lsn > SEG_HEADER_LEN as Lsn);
        assert!(iterated_lsn > snapshot.stable_lsn.unwrap_or(0));

        let segment_progress: Lsn = iterated_lsn % (config.segment_size as Lsn);
        assert!(segment_progress >= SEG_HEADER_LEN as Lsn);

        let (stable_lsn, active_segment) = if segment_progress
            + MAX_MSG_HEADER_LEN as Lsn
            >= config.segment_size as Lsn
        {
            let bumped =
                config.normalize(iter.cur_lsn) + config.segment_size as Lsn;
            trace!("bumping snapshot.stable_lsn to {}", bumped);
            (bumped, None)
        } else {
            if let Some(BasedBuf { offset, .. }) = iter.segment_base {
                // either situation 3 or situation 4. we need to zero the
                // tail of the segment after the recovered tip
                let shred_len = config.segment_size - segment_progress as usize;
                let shred_zone = vec![MessageKind::Corrupted.into(); shred_len];
                let shred_base = offset + segment_progress as LogOffset;
                debug!(
                    "zeroing the end of the recovered segment between {} and {}",
                    shred_base,
                    shred_base + shred_len as LogOffset
                );
                pwrite_all(&config.file, &shred_zone, shred_base)?;
                config.file.sync_all()?;
            }
            (iterated_lsn, iter.segment_base.map(|bb| bb.offset))
        };

        snapshot.stable_lsn = Some(stable_lsn);
        snapshot.active_segment = active_segment;

        snapshot
    };

    trace!("generated snapshot: {:?}", snapshot);

    assert!(snapshot.stable_lsn >= old_stable_lsn);

    if snapshot.stable_lsn > old_stable_lsn {
        write_snapshot(config, &snapshot)?;
    }

    for to_zero in iter.segments.values().copied() {
        debug!("zeroing torn segment at lid {}", to_zero);

        // NB we intentionally corrupt this header to prevent any segment
        // from being allocated which would duplicate its LSN, messing
        // up recovery in the future.
        io_fail!(config, "segment initial free zero");
        pwrite_all(
            &config.file,
            &*vec![MessageKind::Corrupted.into(); config.segment_size],
            to_zero,
        )?;
        if !config.temporary {
            config.file.sync_all()?;
        }
    }

    // remove all blob files larger than our stable offset
    if let Some(stable_lsn) = snapshot.stable_lsn {
        gc_blobs(config, stable_lsn)?;
    }

    #[cfg(feature = "event_log")]
    config.event_log.recovered_lsn(snapshot.stable_lsn);

    Ok(snapshot)
}

/// Read a `Snapshot` or generate a default, then advance it to
/// the tip of the data file, if present.
pub fn read_snapshot_or_default(config: &RunningConfig) -> Result<Snapshot> {
    let last_snap = read_snapshot(config)?.unwrap_or_else(Snapshot::default);

    let log_iter = raw_segment_iter_from(last_snap.stable_lsn, config)?;

    let res = advance_snapshot(log_iter, last_snap, config)?;

    Ok(res)
}

/// Read a `Snapshot` from disk.
fn read_snapshot(config: &RunningConfig) -> std::io::Result<Option<Snapshot>> {
    let mut f = loop {
        let mut candidates = config.get_snapshot_files()?;
        if candidates.is_empty() {
            debug!("no previous snapshot found");
            return Ok(None);
        }

        candidates.sort();

        let path = candidates.pop().unwrap();

        match std::fs::OpenOptions::new().read(true).open(&path) {
            Ok(f) => break f,
            Err(ref e) if e.kind() == std::io::ErrorKind::NotFound => {
                // this can happen if there's a race
                continue;
            }
            Err(other) => return Err(other),
        }
    };

    let mut buf = vec![];
    let _read = f.read_to_end(&mut buf)?;
    let len = buf.len();
    if len <= 12 {
        warn!("empty/corrupt snapshot file found");
        return Ok(None);
    }

    let mut len_expected_bytes = [0; 8];
    len_expected_bytes.copy_from_slice(&buf[len - 12..len - 4]);

    let mut crc_expected_bytes = [0; 4];
    crc_expected_bytes.copy_from_slice(&buf[len - 4..]);

    let _ = buf.split_off(len - 12);
    let crc_expected: u32 = arr_to_u32(&crc_expected_bytes);

    let crc_actual = crc32(&buf);

    if crc_expected != crc_actual {
        return Ok(None);
    }

    #[cfg(feature = "zstd")]
    let bytes = if config.use_compression {
        use std::convert::TryInto;

        let len_expected: u64 =
            u64::from_le_bytes(len_expected_bytes.as_ref().try_into().unwrap());

        decompress(&*buf, usize::try_from(len_expected).unwrap()).unwrap()
    } else {
        buf
    };

    #[cfg(not(feature = "zstd"))]
    let bytes = buf;

    Ok(Snapshot::deserialize(&mut bytes.as_slice()).ok())
}

fn write_snapshot(config: &RunningConfig, snapshot: &Snapshot) -> Result<()> {
    trace!("writing snapshot {:?}", snapshot);

    let raw_bytes = snapshot.serialize();
    let decompressed_len = raw_bytes.len();

    #[cfg(feature = "zstd")]
    let bytes = if config.use_compression {
        compress(&*raw_bytes, config.compression_factor).unwrap()
    } else {
        raw_bytes
    };

    #[cfg(not(feature = "zstd"))]
    let bytes = raw_bytes;

    let crc32: [u8; 4] = u32_to_arr(crc32(&bytes));
    let len_bytes: [u8; 8] = u64_to_arr(decompressed_len as u64);

    let path_1_suffix = format!("snap.{:016X}.generating", snapshot.stable_lsn);

    let mut path_1 = config.get_path();
    path_1.push(path_1_suffix);

    let path_2_suffix = format!("snap.{:016X}", snapshot.stable_lsn);

    let mut path_2 = config.get_path();
    path_2.push(path_2_suffix);

    let parent = path_1.parent().unwrap();
    std::fs::create_dir_all(parent)?;
    let mut f =
        std::fs::OpenOptions::new().write(true).create(true).open(&path_1)?;

    // write the snapshot bytes, followed by a crc64 checksum at the end
    io_fail!(config, "snap write");
    f.write_all(&*bytes)?;
    io_fail!(config, "snap write len");
    f.write_all(&len_bytes)?;
    io_fail!(config, "snap write crc");
    f.write_all(&crc32)?;
    io_fail!(config, "snap write post");
    f.sync_all()?;

    trace!("wrote snapshot to {}", path_1.to_string_lossy());

    io_fail!(config, "snap write mv");
    std::fs::rename(&path_1, &path_2)?;
    io_fail!(config, "snap write mv post");

    trace!("renamed snapshot to {}", path_2.to_string_lossy());

    // clean up any old snapshots
    let candidates = config.get_snapshot_files()?;
    for path in candidates {
        let path_str = path.file_name().unwrap().to_str().unwrap();
        if !path_2.to_string_lossy().ends_with(&*path_str) {
            debug!("removing old snapshot file {:?}", path);

            io_fail!(config, "snap write rm old");

            if let Err(e) = std::fs::remove_file(&path) {
                // TODO should this just be a try return?
                warn!(
                    "failed to remove old snapshot file, maybe snapshot race? {}",
                    e
                );
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>// Std
use std::collections::HashMap;
use std::ffi::OsString;
use std::mem;
use std::ops::Deref;

// Internal
use crate::builder::{Arg, ArgPredicate, Command};
use crate::parser::AnyValue;
use crate::parser::{ArgMatches, MatchedArg, SubCommand, ValueSource};
use crate::util::Id;

// Third party
use indexmap::map::Entry;

#[derive(Debug, Default)]
pub(crate) struct ArgMatcher(ArgMatches);

impl ArgMatcher {
    pub(crate) fn new(_cmd: &Command) -> Self {
        ArgMatcher(ArgMatches {
            #[cfg(debug_assertions)]
            valid_args: {
                let args = _cmd.get_arguments().map(|a| a.id.clone());
                let groups = _cmd.get_groups().map(|g| g.id.clone());
                args.chain(groups).collect()
            },
            #[cfg(debug_assertions)]
            valid_subcommands: _cmd.get_subcommands().map(|sc| sc.get_id()).collect(),
            // HACK: Allow an external subcommand's ArgMatches be a stand-in for any ArgMatches
            // since users can't detect it and avoid the asserts.
            //
            // See clap-rs/clap#3263
            #[cfg(debug_assertions)]
            #[cfg(not(feature = "unstable-v4"))]
            disable_asserts: _cmd.is_allow_external_subcommands_set(),
            #[cfg(debug_assertions)]
            #[cfg(feature = "unstable-v4")]
            disable_asserts: false,
            ..Default::default()
        })
    }

    pub(crate) fn into_inner(self) -> ArgMatches {
        self.0
    }

    pub(crate) fn propagate_globals(&mut self, global_arg_vec: &[Id]) {
        debug!(
            "ArgMatcher::get_global_values: global_arg_vec={:?}",
            global_arg_vec
        );
        let mut vals_map = HashMap::new();
        self.fill_in_global_values(global_arg_vec, &mut vals_map);
    }

    fn fill_in_global_values(
        &mut self,
        global_arg_vec: &[Id],
        vals_map: &mut HashMap<Id, MatchedArg>,
    ) {
        for global_arg in global_arg_vec {
            if let Some(ma) = self.get(global_arg) {
                // We have to check if the parent's global arg wasn't used but still exists
                // such as from a default value.
                //
                // For example, `myprog subcommand --global-arg=value` where --global-arg defines
                // a default value of `other` myprog would have an existing MatchedArg for
                // --global-arg where the value is `other`, however the occurs will be 0.
                let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
                    if parent_ma.get_occurrences() > 0 && ma.get_occurrences() == 0 {
                        parent_ma
                    } else {
                        ma
                    }
                } else {
                    ma
                }
                .clone();
                vals_map.insert(global_arg.clone(), to_update);
            }
        }
        if let Some(ref mut sc) = self.0.subcommand {
            let mut am = ArgMatcher(mem::take(&mut sc.matches));
            am.fill_in_global_values(global_arg_vec, vals_map);
            mem::swap(&mut am.0, &mut sc.matches);
        }

        for (name, matched_arg) in vals_map.iter_mut() {
            self.0.args.insert(name.clone(), matched_arg.clone());
        }
    }

    pub(crate) fn get(&self, arg: &Id) -> Option<&MatchedArg> {
        self.0.args.get(arg)
    }

    pub(crate) fn remove(&mut self, arg: &Id) {
        self.0.args.swap_remove(arg);
    }

    pub(crate) fn contains(&self, arg: &Id) -> bool {
        self.0.args.contains_key(arg)
    }

    pub(crate) fn arg_names(&self) -> indexmap::map::Keys<Id, MatchedArg> {
        self.0.args.keys()
    }

    pub(crate) fn entry(&mut self, arg: &Id) -> indexmap::map::Entry<Id, MatchedArg> {
        self.0.args.entry(arg.clone())
    }

    pub(crate) fn subcommand(&mut self, sc: SubCommand) {
        self.0.subcommand = Some(Box::new(sc));
    }

    pub(crate) fn subcommand_name(&self) -> Option<&str> {
        self.0.subcommand_name()
    }

    pub(crate) fn iter(&self) -> indexmap::map::Iter<Id, MatchedArg> {
        self.0.args.iter()
    }

    pub(crate) fn check_explicit<'a>(&self, arg: &Id, predicate: ArgPredicate<'a>) -> bool {
        self.get(arg).map_or(false, |a| a.check_explicit(predicate))
    }

    pub(crate) fn start_occurrence_of_arg(&mut self, arg: &Arg) {
        let id = &arg.id;
        debug!("ArgMatcher::start_occurrence_of_arg: id={:?}", id);
        let ma = self.entry(id).or_insert(MatchedArg::new());
        ma.set_source(ValueSource::CommandLine);
        ma.set_ignore_case(arg.is_ignore_case_set());
        ma.inc_occurrences();
    }

    pub(crate) fn start_occurrence_of_group(&mut self, id: &Id) {
        debug!("ArgMatcher::start_occurrence_of_group: id={:?}", id);
        let ma = self.entry(id).or_insert(MatchedArg::new());
        ma.set_source(ValueSource::CommandLine);
        ma.inc_occurrences();
    }

    #[cfg(feature = "unstable-v4")]
    pub(crate) fn start_occurrence_of_external(&mut self) {
        let id = &Id::empty_hash();
        debug!("ArgMatcher::start_occurrence_of_external: id={:?}", id,);
        let ma = self.entry(id).or_insert(MatchedArg::new());
        ma.set_source(ValueSource::CommandLine);
        ma.inc_occurrences();
    }

    #[cfg(not(feature = "unstable-v4"))]
    pub(crate) fn start_occurrence_of_external(&mut self) {
        let id = &Id::empty_hash();
        debug!("ArgMatcher::start_occurrence_of_external: id={:?}", id,);
        self.entry(id).or_insert(MatchedArg::new());
    }

    pub(crate) fn add_val_to(
        &mut self,
        arg: &Id,
        val: AnyValue,
        raw_val: OsString,
        ty: ValueSource,
        append: bool,
    ) {
        if append {
            self.append_val_to(arg, val, raw_val, ty);
        } else {
            self.push_val_to(arg, val, raw_val, ty);
        }
    }

    fn push_val_to(&mut self, arg: &Id, val: AnyValue, raw_val: OsString, ty: ValueSource) {
        // We will manually inc occurrences later(for flexibility under
        // specific circumstances, like only add one occurrence for flag
        // when we met: `--flag=one,two`).
        let ma = self.entry(arg).or_default();
        ma.set_source(ty);
        ma.push_val(val, raw_val);
    }

    fn append_val_to(&mut self, arg: &Id, val: AnyValue, raw_val: OsString, ty: ValueSource) {
        let ma = self.entry(arg).or_default();
        ma.set_source(ty);
        ma.append_val(val, raw_val);
    }

    pub(crate) fn new_val_group(&mut self, arg: &Id) {
        let ma = self.entry(arg).or_default();
        ma.new_val_group();
    }

    pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize, ty: ValueSource) {
        let ma = self.entry(arg).or_default();
        ma.set_source(ty);
        ma.push_index(idx);
    }

    pub(crate) fn has_val_groups(&mut self, arg: &Id) -> bool {
        match self.entry(arg) {
            Entry::Occupied(e) => e.get().has_val_groups(),
            Entry::Vacant(_) => false,
        }
    }

    pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool {
        debug!("ArgMatcher::needs_more_vals: o={}", o.name);
        if let Some(ma) = self.get(&o.id) {
            let current_num = ma.num_vals();
            if let Some(num) = o.num_vals {
                debug!("ArgMatcher::needs_more_vals: num_vals...{}", num);
                return if o.is_multiple_occurrences_set() {
                    (current_num % num) != 0
                } else {
                    num != current_num
                };
            } else if let Some(num) = o.max_vals {
                debug!("ArgMatcher::needs_more_vals: max_vals...{}", num);
                return current_num < num;
            } else if o.min_vals.is_some() {
                debug!("ArgMatcher::needs_more_vals: min_vals...true");
                return true;
            }
            return o.is_multiple_values_set();
        }
        true
    }
}

impl Deref for ArgMatcher {
    type Target = ArgMatches;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
<commit_msg>fix(parser): Set source/occurrences for external subcommands<commit_after>// Std
use std::collections::HashMap;
use std::ffi::OsString;
use std::mem;
use std::ops::Deref;

// Internal
use crate::builder::{Arg, ArgPredicate, Command};
use crate::parser::AnyValue;
use crate::parser::{ArgMatches, MatchedArg, SubCommand, ValueSource};
use crate::util::Id;

// Third party
use indexmap::map::Entry;

#[derive(Debug, Default)]
pub(crate) struct ArgMatcher(ArgMatches);

impl ArgMatcher {
    pub(crate) fn new(_cmd: &Command) -> Self {
        ArgMatcher(ArgMatches {
            #[cfg(debug_assertions)]
            valid_args: {
                let args = _cmd.get_arguments().map(|a| a.id.clone());
                let groups = _cmd.get_groups().map(|g| g.id.clone());
                args.chain(groups).collect()
            },
            #[cfg(debug_assertions)]
            valid_subcommands: _cmd.get_subcommands().map(|sc| sc.get_id()).collect(),
            // HACK: Allow an external subcommand's ArgMatches be a stand-in for any ArgMatches
            // since users can't detect it and avoid the asserts.
            //
            // See clap-rs/clap#3263
            #[cfg(debug_assertions)]
            #[cfg(not(feature = "unstable-v4"))]
            disable_asserts: _cmd.is_allow_external_subcommands_set(),
            #[cfg(debug_assertions)]
            #[cfg(feature = "unstable-v4")]
            disable_asserts: false,
            ..Default::default()
        })
    }

    pub(crate) fn into_inner(self) -> ArgMatches {
        self.0
    }

    pub(crate) fn propagate_globals(&mut self, global_arg_vec: &[Id]) {
        debug!(
            "ArgMatcher::get_global_values: global_arg_vec={:?}",
            global_arg_vec
        );
        let mut vals_map = HashMap::new();
        self.fill_in_global_values(global_arg_vec, &mut vals_map);
    }

    fn fill_in_global_values(
        &mut self,
        global_arg_vec: &[Id],
        vals_map: &mut HashMap<Id, MatchedArg>,
    ) {
        for global_arg in global_arg_vec {
            if let Some(ma) = self.get(global_arg) {
                // We have to check if the parent's global arg wasn't used but still exists
                // such as from a default value.
                //
                // For example, `myprog subcommand --global-arg=value` where --global-arg defines
                // a default value of `other` myprog would have an existing MatchedArg for
                // --global-arg where the value is `other`, however the occurs will be 0.
                let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
                    if parent_ma.get_occurrences() > 0 && ma.get_occurrences() == 0 {
                        parent_ma
                    } else {
                        ma
                    }
                } else {
                    ma
                }
                .clone();
                vals_map.insert(global_arg.clone(), to_update);
            }
        }
        if let Some(ref mut sc) = self.0.subcommand {
            let mut am = ArgMatcher(mem::take(&mut sc.matches));
            am.fill_in_global_values(global_arg_vec, vals_map);
            mem::swap(&mut am.0, &mut sc.matches);
        }

        for (name, matched_arg) in vals_map.iter_mut() {
            self.0.args.insert(name.clone(), matched_arg.clone());
        }
    }

    pub(crate) fn get(&self, arg: &Id) -> Option<&MatchedArg> {
        self.0.args.get(arg)
    }

    pub(crate) fn remove(&mut self, arg: &Id) {
        self.0.args.swap_remove(arg);
    }

    pub(crate) fn contains(&self, arg: &Id) -> bool {
        self.0.args.contains_key(arg)
    }

    pub(crate) fn arg_names(&self) -> indexmap::map::Keys<Id, MatchedArg> {
        self.0.args.keys()
    }

    pub(crate) fn entry(&mut self, arg: &Id) -> indexmap::map::Entry<Id, MatchedArg> {
        self.0.args.entry(arg.clone())
    }

    pub(crate) fn subcommand(&mut self, sc: SubCommand) {
        self.0.subcommand = Some(Box::new(sc));
    }

    pub(crate) fn subcommand_name(&self) -> Option<&str> {
        self.0.subcommand_name()
    }

    pub(crate) fn iter(&self) -> indexmap::map::Iter<Id, MatchedArg> {
        self.0.args.iter()
    }

    pub(crate) fn check_explicit<'a>(&self, arg: &Id, predicate: ArgPredicate<'a>) -> bool {
        self.get(arg).map_or(false, |a| a.check_explicit(predicate))
    }

    pub(crate) fn start_occurrence_of_arg(&mut self, arg: &Arg) {
        let id = &arg.id;
        debug!("ArgMatcher::start_occurrence_of_arg: id={:?}", id);
        let ma = self.entry(id).or_insert(MatchedArg::new());
        ma.set_source(ValueSource::CommandLine);
        ma.set_ignore_case(arg.is_ignore_case_set());
        ma.inc_occurrences();
    }

    pub(crate) fn start_occurrence_of_group(&mut self, id: &Id) {
        debug!("ArgMatcher::start_occurrence_of_group: id={:?}", id);
        let ma = self.entry(id).or_insert(MatchedArg::new());
        ma.set_source(ValueSource::CommandLine);
        ma.inc_occurrences();
    }

    pub(crate) fn start_occurrence_of_external(&mut self) {
        let id = &Id::empty_hash();
        debug!("ArgMatcher::start_occurrence_of_external: id={:?}", id,);
        let ma = self.entry(id).or_insert(MatchedArg::new());
        ma.set_source(ValueSource::CommandLine);
        ma.inc_occurrences();
    }

    pub(crate) fn add_val_to(
        &mut self,
        arg: &Id,
        val: AnyValue,
        raw_val: OsString,
        ty: ValueSource,
        append: bool,
    ) {
        if append {
            self.append_val_to(arg, val, raw_val, ty);
        } else {
            self.push_val_to(arg, val, raw_val, ty);
        }
    }

    fn push_val_to(&mut self, arg: &Id, val: AnyValue, raw_val: OsString, ty: ValueSource) {
        // We will manually inc occurrences later(for flexibility under
        // specific circumstances, like only add one occurrence for flag
        // when we met: `--flag=one,two`).
        let ma = self.entry(arg).or_default();
        ma.set_source(ty);
        ma.push_val(val, raw_val);
    }

    fn append_val_to(&mut self, arg: &Id, val: AnyValue, raw_val: OsString, ty: ValueSource) {
        let ma = self.entry(arg).or_default();
        ma.set_source(ty);
        ma.append_val(val, raw_val);
    }

    pub(crate) fn new_val_group(&mut self, arg: &Id) {
        let ma = self.entry(arg).or_default();
        ma.new_val_group();
    }

    pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize, ty: ValueSource) {
        let ma = self.entry(arg).or_default();
        ma.set_source(ty);
        ma.push_index(idx);
    }

    pub(crate) fn has_val_groups(&mut self, arg: &Id) -> bool {
        match self.entry(arg) {
            Entry::Occupied(e) => e.get().has_val_groups(),
            Entry::Vacant(_) => false,
        }
    }

    pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool {
        debug!("ArgMatcher::needs_more_vals: o={}", o.name);
        if let Some(ma) = self.get(&o.id) {
            let current_num = ma.num_vals();
            if let Some(num) = o.num_vals {
                debug!("ArgMatcher::needs_more_vals: num_vals...{}", num);
                return if o.is_multiple_occurrences_set() {
                    (current_num % num) != 0
                } else {
                    num != current_num
                };
            } else if let Some(num) = o.max_vals {
                debug!("ArgMatcher::needs_more_vals: max_vals...{}", num);
                return current_num < num;
            } else if o.min_vals.is_some() {
                debug!("ArgMatcher::needs_more_vals: min_vals...true");
                return true;
            }
            return o.is_multiple_values_set();
        }
        true
    }
}

impl Deref for ArgMatcher {
    type Target = ArgMatches;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
<|endoftext|>


<commit_before>use std::fs::{remove_file, File};
use std::io::Write;
use std::sync::mpsc::Receiver;
use std::thread;

use crate::game_object::GameObjectRef;

pub enum PersistenceRequest {
    PersistObject(GameObjectRef, String),
    RemoveObject(GameObjectRef),
}

pub fn create_persistence_thread(data_dir: String, persist_rx: Receiver<PersistenceRequest>) {
    thread::spawn(move || {
        while let Ok(peristence_req) = persist_rx.recv() {
            match peristence_req {
                PersistenceRequest::PersistObject(object_ref, data) => {
                    match File::create(format!("{}/{}", data_dir, object_ref.to_file_name())) {
                        Ok(mut file) => {
                            file.write_all(data.as_bytes());
                        }

                        Err(error) => {
                            println!("Cannot persist object {:?}: {:?}", object_ref, error);
                        }
                    }
                }

                PersistenceRequest::RemoveObject(object_ref) => {
                    if let Err(error) =
                        remove_file(format!("{}/{}", data_dir, object_ref.to_file_name()))
                    {
                        println!("Cannot remove object {:?}: {:?}", object_ref, error);
                    }
                }
            }
        }
    });
}
<commit_msg>Handle persistence errors<commit_after>use std::fs::{remove_file, File};
use std::io::Write;
use std::sync::mpsc::Receiver;
use std::thread;

use crate::game_object::GameObjectRef;

pub enum PersistenceRequest {
    PersistObject(GameObjectRef, String),
    RemoveObject(GameObjectRef),
}

pub fn create_persistence_thread(data_dir: String, persist_rx: Receiver<PersistenceRequest>) {
    thread::spawn(move || {
        while let Ok(peristence_req) = persist_rx.recv() {
            match peristence_req {
                PersistenceRequest::PersistObject(object_ref, data) => {
                    let result =
                        File::create(format!("{}/{}", data_dir, object_ref.to_file_name()))
                            .and_then(|mut file| file.write_all(data.as_bytes()));
                    if let Err(error) = result {
                        println!("Cannot persist object {:?}: {:?}", object_ref, error);
                    }
                }

                PersistenceRequest::RemoveObject(object_ref) => {
                    if let Err(error) =
                        remove_file(format!("{}/{}", data_dir, object_ref.to_file_name()))
                    {
                        println!("Cannot remove object {:?}: {:?}", object_ref, error);
                    }
                }
            }
        }
    });
}
<|endoftext|>


<commit_before>use rustwlc::{ResizeEdge, WlcView, Geometry, Point};
use rustwlc::types::VIEW_ACTIVATED;
use nix::libc::pid_t;

/// A lock screen program, that has been spawned by Way Cooler.
///
/// The PID is what is returned from spawning the subprocess.
///
/// The view is optional, because after spawning it we must find it in the
/// `view_created` callback.
pub struct LockScreen {
    /// Pid of the lock screen program.
    pid: pid_t,
    /// The view that is associated with the lock screen program, if it has been located.
    view: Option<WlcView>
}

impl LockScreen {
    /// Creates a new Lock Screen from the PID
    ///
    /// The view is set to `None`, because we haven't found it yet in the
    /// `view_created` callback. This should be updated once it is found,
    /// so that we can start locking the screen.
    pub fn new(pid: pid_t) -> Self {
        LockScreen {
            pid: pid,
            view: None
        }
    }

    pub fn view(&self) -> Option<WlcView> {
        self.view
    }

    /// Returns true the `view` is set, indicating we have found the `WlcView`
    /// associated with the PID.
    pub fn is_locked(&self) -> bool {
        self.view.is_some()
    }

    /// Adds the view to the `LockScreen` if it's PID matches the stored one.
    ///
    /// If there is already here, false is always returned.
    ///
    /// If the view's PID matches this PID, then it's automatically focused,
    /// and the geometry of it is set to the size of it's `WlcOutput`'s size.
    pub fn add_view_if_match(&mut self, view: WlcView) -> bool {
        if self.view.is_some() {
            return false
        }
        if view.get_pid() == self.pid {
            let output = view.get_output();
            let resolution = output.get_resolution()
                .expect("Output was invalid: had no resolution");
            let geo = Geometry {
                origin: Point { x: 0, y: 0 },
                size: resolution
            };
            view.set_geometry(ResizeEdge::empty(), geo);
            view.set_state(VIEW_ACTIVATED, true);
            view.focus();
            view.set_mask(1);
            view.bring_to_front();
            self.view = Some(view);
            true
        } else {
            false
        }
    }

    /// Removes the lockscreen if provided view matches the stored view.
    ///
    /// Does not compare the PID, because the passed in `WlcView` should be
    /// considered invalidated because this function is probably being called
    /// from `view_destroyed`.
    ///
    /// To protect against failing programs, the child handler should be
    /// checked to see if the program is still running.
    /// HOWEVER, this is blocked because this is still a nightly feature.
    /// See https://github.com/rust-lang/rust/issues/38903
    pub fn remove_if_match(self, view: WlcView) -> Option<Self> {
        if self.view == Some(view) {
            None
        } else {
            Some(self)
        }
    }
}
<commit_msg>Fixed warnings<commit_after>use rustwlc::{ResizeEdge, WlcView, Geometry, Point};
use rustwlc::types::VIEW_ACTIVATED;
use nix::libc::pid_t;

/// A lock screen program, that has been spawned by Way Cooler.
///
/// The PID is what is returned from spawning the subprocess.
///
/// The view is optional, because after spawning it we must find it in the
/// `view_created` callback.
pub struct LockScreen {
    /// Pid of the lock screen program.
    pid: pid_t,
    /// The view that is associated with the lock screen program, if it has been located.
    view: Option<WlcView>
}

impl LockScreen {
    /// Creates a new Lock Screen from the PID
    ///
    /// The view is set to `None`, because we haven't found it yet in the
    /// `view_created` callback. This should be updated once it is found,
    /// so that we can start locking the screen.
    pub fn new(pid: pid_t) -> Self {
        LockScreen {
            pid: pid,
            view: None
        }
    }

    pub fn view(&self) -> Option<WlcView> {
        self.view
    }

    /// Adds the view to the `LockScreen` if it's PID matches the stored one.
    ///
    /// If there is already here, false is always returned.
    ///
    /// If the view's PID matches this PID, then it's automatically focused,
    /// and the geometry of it is set to the size of it's `WlcOutput`'s size.
    pub fn add_view_if_match(&mut self, view: WlcView) -> bool {
        if self.view.is_some() {
            return false
        }
        if view.get_pid() == self.pid {
            let output = view.get_output();
            let resolution = output.get_resolution()
                .expect("Output was invalid: had no resolution");
            let geo = Geometry {
                origin: Point { x: 0, y: 0 },
                size: resolution
            };
            view.set_geometry(ResizeEdge::empty(), geo);
            view.set_state(VIEW_ACTIVATED, true);
            view.focus();
            view.set_mask(1);
            view.bring_to_front();
            self.view = Some(view);
            true
        } else {
            false
        }
    }

    /// Removes the lockscreen if provided view matches the stored view.
    ///
    /// Does not compare the PID, because the passed in `WlcView` should be
    /// considered invalidated because this function is probably being called
    /// from `view_destroyed`.
    ///
    /// To protect against failing programs, the child handler should be
    /// checked to see if the program is still running.
    /// HOWEVER, this is blocked because this is still a nightly feature.
    /// See https://github.com/rust-lang/rust/issues/38903
    pub fn remove_if_match(self, view: WlcView) -> Option<Self> {
        if self.view == Some(view) {
            None
        } else {
            Some(self)
        }
    }
}
<|endoftext|>