<commit_before>// Copyright 2013-2014 The Num-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![deny(missing_docs)]

//! Fundamental algebraic structures
//!
//! ~~~notrust
//! |(• ◡•)|ノ〵(❍ᴥ❍⋃)     - "ALGEBRAIC!!!"
//! ~~~
//!
//! For most applications requiring an abstraction over the reals, `FieldApprox`
//! should be suffient.
//!
//! # Fundamental algebraic structures
//!
//! Most of these traits also come in an approximate flavor for types that do
//! not satisfy the required properties exactly, but would still benefit from
//! abstractions over the structure in question.
//!
//! ## Identity elements
//!
//! Two traits are provided that allow the definition of the additive and
//! multiplicative identity elements:
//!
//! - `IdentityAdditive`
//! - `IdentityMultiplicative`
//!
//! ## Group-like structures
//!
//! These structures are provided for both the addition and multiplication.
//!
//! ~~~notrust
//!               Magma
//!                 |
//!         _______/ \______
//!        /                \
//!   divisiblity      associativity
//!       |                  |
//!       V                  V
//!  Quasigroup          Semigroup
//!       |                  |
//!   identity            identity
//!       |                  |
//!       V                  V
//!     Loop               Monoid
//!       |                  |
//!  associative     invertablility
//!        \______   _______/
//!               \ /
//!                |
//!                V
//!              Group
//!                |
//!          commutativity
//!                |
//!                V
//!           AbelianGroup
//! ~~~
//!
//! The following traits are provided:
//!
//! -      `Closure`(`Additive`|`Multiplicative`)(`Approx`)?
//! -        `Magma`(`Additive`|`Multiplicative`)(`Approx`)?
//! -   `Quasigroup`(`Additive`|`Multiplicative`)(`Approx`)?
//! -         `Loop`(`Additive`|`Multiplicative`)(`Approx`)?
//! -    `Semigroup`(`Additive`|`Multiplicative`)(`Approx`)?
//! -       `Monoid`(`Additive`|`Multiplicative`)(`Approx`)?
//! -        `Group`(`Additive`|`Multiplicative`)(`Approx`)?
//! - `AbelianGroup`(`Additive`|`Multiplicative`)(`Approx`)?
//!
//! ## Ring-like structures
//!
//! ~~~notrust
//! GroupAdditiveAbelian     MonoidMultiplicative
//!           \________   ________/
//!                    \ /
//!                     |
//!                     V
//!                    Ring
//!                     |
//!            commutativity_of_mul
//!                     |
//!                     V
//!              RingCommutative     GroupMultiplicativeAbelian
//!                      \_______   ___________/
//!                              \ /
//!                               |
//!                               V
//!                             Field
//! ~~~
//!
//! The following traits are provided:
//!
//! -            `Ring`(`Approx`)?
//! - `RingCommutative`(`Approx`)?
//! -           `Field`(`Approx`)?
//!
//! # Quickcheck properties
//!
//! Functions are provided to test that algebraic properties like
//! assciociativity and commutativity hold for a given set of arguments.
//!
//! For example:
//!
//! ~~~
//! # use algebra::structure::SemigroupMultiplicativeApprox;
//! #[quickcheck]
//! fn prop_mul_is_associative_approx(args: (i32, i32, i32)) -> bool {
//!     SemigroupMultiplicativeApprox::prop_mul_is_associative_approx(args)
//! }
//! ~~~

pub use self::ident::{IdentityAdditive, zero};
pub use self::ident::{IdentityMultiplicative, unit};

pub use self::magma::MagmaAdditiveApprox;
pub use self::magma::MagmaMultiplicativeApprox;
pub use self::magma::MagmaAdditive;
pub use self::magma::MagmaMultiplicative;

pub use self::quasigroup::QuasigroupAdditiveApprox;
pub use self::quasigroup::QuasigroupMultiplicativeApprox;
pub use self::quasigroup::QuasigroupAdditive;
pub use self::quasigroup::QuasigroupMultiplicative;

pub use self::loop_::LoopAdditiveApprox;
pub use self::loop_::LoopMultiplicativeApprox;
pub use self::loop_::LoopAdditive;
pub use self::loop_::LoopMultiplicative;

pub use self::semigroup::SemigroupAdditiveApprox;
pub use self::semigroup::SemigroupMultiplicativeApprox;
pub use self::semigroup::SemigroupAdditive;
pub use self::semigroup::SemigroupMultiplicative;

pub use self::monoid::MonoidAdditiveApprox;
pub use self::monoid::MonoidMultiplicativeApprox;
pub use self::monoid::MonoidAdditive;
pub use self::monoid::MonoidMultiplicative;

pub use self::group::GroupAdditiveApprox;
pub use self::group::GroupMultiplicativeApprox;
pub use self::group::GroupAdditive;
pub use self::group::GroupMultiplicative;

pub use self::abelian::GroupAdditiveAbelianApprox;
pub use self::abelian::GroupMultiplicativeAbelianApprox;
pub use self::abelian::GroupAdditiveAbelian;
pub use self::abelian::GroupMultiplicativeAbelian;

pub use self::ring::RingApprox;
pub use self::ring::Ring;
pub use self::ring::RingCommutativeApprox;
pub use self::ring::RingCommutative;
pub use self::ring::FieldApprox;
pub use self::ring::Field;

pub use self::module::ModuleApprox;
pub use self::module::Module;
pub use self::module::VectorApprox;
pub use self::module::Vector;

mod ident;

mod magma;
mod quasigroup;
mod loop_;
mod semigroup;
mod monoid;
mod group;
mod abelian;
mod ring;
mod module;
<commit_msg>Added documentation.<commit_after>// Copyright 2013-2014 The Num-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![deny(missing_docs)]

//! Fundamental algebraic structures
//!
//! ~~~notrust
//! |(• ◡•)|ノ〵(❍ᴥ❍⋃)     - "ALGEBRAIC!!!"
//! ~~~
//!
//! For most applications requiring an abstraction over the reals, `FieldApprox`
//! should be suffient.
//!
//! # Fundamental algebraic structures
//!
//! Most of these traits also come in an approximate flavor for types that do
//! not satisfy the required properties exactly, but would still benefit from
//! abstractions over the structure in question.
//!
//! ## Identity elements
//!
//! Two traits are provided that allow the definition of the additive and
//! multiplicative identity elements:
//!
//! - `IdentityAdditive`
//! - `IdentityMultiplicative`
//!
//! ## Group-like structures
//!
//! These structures are provided for both the addition and multiplication.
//!
//! ~~~notrust
//!               Magma
//!                 |
//!         _______/ \______
//!        /                \
//!   divisiblity      associativity
//!       |                  |
//!       V                  V
//!  Quasigroup          Semigroup
//!       |                  |
//!   identity            identity
//!       |                  |
//!       V                  V
//!     Loop               Monoid
//!       |                  |
//!  associative     invertablility
//!        \______   _______/
//!               \ /
//!                |
//!                V
//!              Group
//!                |
//!          commutativity
//!                |
//!                V
//!           AbelianGroup
//! ~~~
//!
//! The following traits are provided:
//!
//! -      `Closure`(`Additive`|`Multiplicative`)(`Approx`)?
//! -        `Magma`(`Additive`|`Multiplicative`)(`Approx`)?
//! -   `Quasigroup`(`Additive`|`Multiplicative`)(`Approx`)?
//! -         `Loop`(`Additive`|`Multiplicative`)(`Approx`)?
//! -    `Semigroup`(`Additive`|`Multiplicative`)(`Approx`)?
//! -       `Monoid`(`Additive`|`Multiplicative`)(`Approx`)?
//! -        `Group`(`Additive`|`Multiplicative`)(`Approx`)?
//! - `AbelianGroup`(`Additive`|`Multiplicative`)(`Approx`)?
//!
//! ## Ring-like structures
//!
//! ~~~notrust
//! GroupAdditiveAbelian     MonoidMultiplicative
//!           \________   ________/
//!                    \ /
//!                     |
//!                     V
//!                    Ring
//!                     |
//!            commutativity_of_mul
//!                     |
//!                     V
//!              RingCommutative     GroupMultiplicativeAbelian
//!                      \_______   ___________/
//!                              \ /
//!                               |
//!                               V
//!                             Field
//! ~~~
//!
//! The following traits are provided:
//!
//! -            `Ring`(`Approx`)?
//! - `RingCommutative`(`Approx`)?
//! -           `Field`(`Approx`)?
//!
//! ## Module-like structures
//!
//! ~~~notrust
//! GroupAdditiveAbelian     RingCommutative
//!           \______         _____/
//!                  \       /
//!                   |     |
//!                   V     V
//!                Module<Scalar>          Field
//!                    \______         _____/
//!                           \       /
//!                            |     |
//!                            V     V
//!                         Vector<Scalar>
//! ~~~
//!
//! The following traits are provided:
//!
//! - `Module`(`Approx`)?
//! - `Vector`(`Approx`)?
//!
//! # Quickcheck properties
//!
//! Functions are provided to test that algebraic properties like
//! assciociativity and commutativity hold for a given set of arguments.
//!
//! For example:
//!
//! ~~~
//! # use algebra::structure::SemigroupMultiplicativeApprox;
//! #[quickcheck]
//! fn prop_mul_is_associative_approx(args: (i32, i32, i32)) -> bool {
//!     SemigroupMultiplicativeApprox::prop_mul_is_associative_approx(args)
//! }
//! ~~~

pub use self::ident::{IdentityAdditive, zero};
pub use self::ident::{IdentityMultiplicative, unit};

pub use self::magma::MagmaAdditiveApprox;
pub use self::magma::MagmaMultiplicativeApprox;
pub use self::magma::MagmaAdditive;
pub use self::magma::MagmaMultiplicative;

pub use self::quasigroup::QuasigroupAdditiveApprox;
pub use self::quasigroup::QuasigroupMultiplicativeApprox;
pub use self::quasigroup::QuasigroupAdditive;
pub use self::quasigroup::QuasigroupMultiplicative;

pub use self::loop_::LoopAdditiveApprox;
pub use self::loop_::LoopMultiplicativeApprox;
pub use self::loop_::LoopAdditive;
pub use self::loop_::LoopMultiplicative;

pub use self::semigroup::SemigroupAdditiveApprox;
pub use self::semigroup::SemigroupMultiplicativeApprox;
pub use self::semigroup::SemigroupAdditive;
pub use self::semigroup::SemigroupMultiplicative;

pub use self::monoid::MonoidAdditiveApprox;
pub use self::monoid::MonoidMultiplicativeApprox;
pub use self::monoid::MonoidAdditive;
pub use self::monoid::MonoidMultiplicative;

pub use self::group::GroupAdditiveApprox;
pub use self::group::GroupMultiplicativeApprox;
pub use self::group::GroupAdditive;
pub use self::group::GroupMultiplicative;

pub use self::abelian::GroupAdditiveAbelianApprox;
pub use self::abelian::GroupMultiplicativeAbelianApprox;
pub use self::abelian::GroupAdditiveAbelian;
pub use self::abelian::GroupMultiplicativeAbelian;

pub use self::ring::RingApprox;
pub use self::ring::Ring;
pub use self::ring::RingCommutativeApprox;
pub use self::ring::RingCommutative;
pub use self::ring::FieldApprox;
pub use self::ring::Field;

pub use self::module::ModuleApprox;
pub use self::module::Module;
pub use self::module::VectorApprox;
pub use self::module::Vector;

mod ident;

mod magma;
mod quasigroup;
mod loop_;
mod semigroup;
mod monoid;
mod group;
mod abelian;
mod ring;
mod module;
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Genymobile
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::net::{SocketAddr, TcpStream};
use std::io::{self, Write};
use std::process;
use std::str;
use std::thread;
use std::time::Duration;
use relaylib::byte_buffer::ByteBuffer;

const TAG: &'static str = "AdbMonitor";

pub trait AdbMonitorCallback {
    fn on_new_device_connected(&self, serial: &String);
}

impl<F> AdbMonitorCallback for F
where
    F: Fn(&String),
{
    fn on_new_device_connected(&self, serial: &String) {
        self(serial);
    }
}
pub struct AdbMonitor {
    callback: Box<AdbMonitorCallback>,
    buf: ByteBuffer,
}

impl AdbMonitor {
    const TRACK_DEVICES_REQUEST: &'static [u8] = b"0012host:track-devices";
    const BUFFER_SIZE: usize = 1024;
    const RETRY_DELAY_ADB_DAEMON_OK: u64 = 1000;
    const RETRY_DELAY_ADB_DAEMON_KO: u64 = 5000;

    pub fn new(callback: Box<AdbMonitorCallback>) -> Self {
        Self {
            callback: callback,
            buf: ByteBuffer::new(Self::BUFFER_SIZE),
        }
    }

    pub fn monitor(&mut self) -> io::Result<()> {
        loop {
            if let Err(err) = self.track_devices() {
                error!(target: TAG, "Failed to monitor adb devices: {}", err);
                Self::repair_adb_daemon();
            }
        }
    }

    fn track_devices(&mut self) -> io::Result<()> {
        let adbd_addr = SocketAddr::from(([127, 0, 0, 1], 5037));
        let mut stream = TcpStream::connect(adbd_addr)?;
        self.track_devices_on_stream(&mut stream)
    }

    fn track_devices_on_stream(&mut self, stream: &mut TcpStream) -> io::Result<()> {
        stream.write_all(Self::TRACK_DEVICES_REQUEST)?;
        if self.consume_okay(stream)? {
            loop {
                let packet = self.next_packet(stream)?;
                self.handle_packet(&packet);
            }
        }
        Ok(())
    }

    fn consume_okay(&mut self, stream: &mut TcpStream) -> io::Result<bool> {
        while self.buf.peek().len() < 4 {
            self.buf.read_from(stream)?;
        }
        let ok = b"OKAY" == &self.buf.peek()[0..4];
        self.buf.consume(4);
        Ok(ok)
    }

    fn read_packet(buf: &mut ByteBuffer) -> io::Result<Option<String>> {
        let packet_length = Self::available_packet_length(buf.peek())?;
        if let Some(len) = packet_length {
            // retrieve the content and consume the packet
            let data = Self::to_string(&buf.peek()[4..len])?;
            buf.consume(len);
            Ok(Some(data))
        } else {
            Ok(None)
        }
    }

    fn next_packet(&mut self, stream: &mut TcpStream) -> io::Result<String> {
        loop {
            let packet = Self::read_packet(&mut self.buf)?;
            if let Some(packet) = packet {
                return Ok(packet);
            } else {
                self.fill_buffer_from(stream)?;
            }
        }
    }

    fn fill_buffer_from(&mut self, stream: &mut TcpStream) -> io::Result<()> {
        match self.buf.read_from(stream) {
            Ok(false) => Err(io::Error::new(
                io::ErrorKind::UnexpectedEof,
                "ADB daemon closed the track-devices connexion",
            )),
            Ok(_) => Ok(()),
            Err(err) => Err(err),
        }
    }

    fn available_packet_length(input: &[u8]) -> io::Result<Option<usize>> {
        if input.len() < 4 {
            Ok(None)
        } else {
            // each packet contains 4 bytes representing the String length in hexa, followed by the
            // device serial, `\t', the state, '\n'
            // for example: "00180123456789abcdef\tdevice\n": 0018 indicates that the data is 0x18
            // (24) bytes length
            let len = Self::parse_length(&input[0..4])?;
            if len > Self::BUFFER_SIZE as u32 {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidInput,
                    format!("Packet size should not be that big: {}", len),
                ));
            }
            if input.len() - 4usize >= len as usize {
                Ok(Some(4usize + len as usize))
            } else {
                // not enough data
                Ok(None)
            }
        }
    }

    fn handle_packet(&self, serial: &String) {
        let mut split = serial.split_whitespace();
        if let Some(serial) = split.next() {
            if let Some(state) = split.next() {
                if "device" == state {
                    self.callback.on_new_device_connected(&serial.to_string());
                }
            }
        }
    }

    fn parse_length(data: &[u8]) -> io::Result<u32> {
        assert!(data.len() == 4, "Invalid length field value");
        let hexa = str::from_utf8(data).map_err(|err| {
            io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("Cannot read hexa length as UTF-8 ({})", err),
            )
        })?;
        u32::from_str_radix(hexa, 0x10).map_err(|err| {
            io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("Cannot parse hexa length ({})", err),
            )
        })
    }

    fn repair_adb_daemon() {
        if Self::start_adb_daemon() {
            thread::sleep(Duration::from_millis(Self::RETRY_DELAY_ADB_DAEMON_OK));
        } else {
            thread::sleep(Duration::from_millis(Self::RETRY_DELAY_ADB_DAEMON_KO));
        }
    }

    fn start_adb_daemon() -> bool {
        info!(target: TAG, "Restarting adb daemon");
        match process::Command::new("adb")
            .args(&["start-server"])
            .status() {
            Ok(exit_status) => {
                if exit_status.success() {
                    true
                } else {
                    error!(
                        target: TAG,
                        "Could not restart adb daemon (exited on error)"
                    );
                    false
                }
            }
            Err(err) => {
                error!(target: TAG, "Could not restart adb daemon: {}", err);
                false
            }
        }
    }

    fn to_string(data: &[u8]) -> io::Result<String> {
        let raw_content = data.to_vec();
        let content = String::from_utf8(raw_content);
        if let Ok(content) = content {
            Ok(content)
        } else {
            Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Track-devices string is not valid UTF-8",
            ))
        }
    }
}
<commit_msg>Add unit tests for Rust AdbMonitor<commit_after>/*
 * Copyright (C) 2017 Genymobile
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::net::{SocketAddr, TcpStream};
use std::io::{self, Write};
use std::process;
use std::str;
use std::thread;
use std::time::Duration;
use relaylib::byte_buffer::ByteBuffer;

const TAG: &'static str = "AdbMonitor";

pub trait AdbMonitorCallback {
    fn on_new_device_connected(&self, serial: &String);
}

impl<F> AdbMonitorCallback for F
where
    F: Fn(&String),
{
    fn on_new_device_connected(&self, serial: &String) {
        self(serial);
    }
}
pub struct AdbMonitor {
    callback: Box<AdbMonitorCallback>,
    buf: ByteBuffer,
}

impl AdbMonitor {
    const TRACK_DEVICES_REQUEST: &'static [u8] = b"0012host:track-devices";
    const BUFFER_SIZE: usize = 1024;
    const RETRY_DELAY_ADB_DAEMON_OK: u64 = 1000;
    const RETRY_DELAY_ADB_DAEMON_KO: u64 = 5000;

    pub fn new(callback: Box<AdbMonitorCallback>) -> Self {
        Self {
            callback: callback,
            buf: ByteBuffer::new(Self::BUFFER_SIZE),
        }
    }

    pub fn monitor(&mut self) -> io::Result<()> {
        loop {
            if let Err(err) = self.track_devices() {
                error!(target: TAG, "Failed to monitor adb devices: {}", err);
                Self::repair_adb_daemon();
            }
        }
    }

    fn track_devices(&mut self) -> io::Result<()> {
        let adbd_addr = SocketAddr::from(([127, 0, 0, 1], 5037));
        let mut stream = TcpStream::connect(adbd_addr)?;
        self.track_devices_on_stream(&mut stream)
    }

    fn track_devices_on_stream(&mut self, stream: &mut TcpStream) -> io::Result<()> {
        stream.write_all(Self::TRACK_DEVICES_REQUEST)?;
        if self.consume_okay(stream)? {
            loop {
                let packet = self.next_packet(stream)?;
                self.handle_packet(&packet);
            }
        }
        Ok(())
    }

    fn consume_okay(&mut self, stream: &mut TcpStream) -> io::Result<bool> {
        while self.buf.peek().len() < 4 {
            self.buf.read_from(stream)?;
        }
        let ok = b"OKAY" == &self.buf.peek()[0..4];
        self.buf.consume(4);
        Ok(ok)
    }

    fn read_packet(buf: &mut ByteBuffer) -> io::Result<Option<String>> {
        let packet_length = Self::available_packet_length(buf.peek())?;
        if let Some(len) = packet_length {
            // retrieve the content and consume the packet
            let data = Self::to_string(&buf.peek()[4..len])?;
            buf.consume(len);
            Ok(Some(data))
        } else {
            Ok(None)
        }
    }

    fn next_packet(&mut self, stream: &mut TcpStream) -> io::Result<String> {
        loop {
            let packet = Self::read_packet(&mut self.buf)?;
            if let Some(packet) = packet {
                return Ok(packet);
            } else {
                self.fill_buffer_from(stream)?;
            }
        }
    }

    fn fill_buffer_from(&mut self, stream: &mut TcpStream) -> io::Result<()> {
        match self.buf.read_from(stream) {
            Ok(false) => Err(io::Error::new(
                io::ErrorKind::UnexpectedEof,
                "ADB daemon closed the track-devices connexion",
            )),
            Ok(_) => Ok(()),
            Err(err) => Err(err),
        }
    }

    fn available_packet_length(input: &[u8]) -> io::Result<Option<usize>> {
        if input.len() < 4 {
            Ok(None)
        } else {
            // each packet contains 4 bytes representing the String length in hexa, followed by the
            // device serial, `\t', the state, '\n'
            // for example: "00180123456789abcdef\tdevice\n": 0018 indicates that the data is 0x18
            // (24) bytes length
            let len = Self::parse_length(&input[0..4])?;
            if len > Self::BUFFER_SIZE as u32 {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidInput,
                    format!("Packet size should not be that big: {}", len),
                ));
            }
            if input.len() - 4usize >= len as usize {
                Ok(Some(4usize + len as usize))
            } else {
                // not enough data
                Ok(None)
            }
        }
    }

    fn handle_packet(&self, serial: &String) {
        let mut split = serial.split_whitespace();
        if let Some(serial) = split.next() {
            if let Some(state) = split.next() {
                if "device" == state {
                    self.callback.on_new_device_connected(&serial.to_string());
                }
            }
        }
    }

    fn parse_length(data: &[u8]) -> io::Result<u32> {
        assert!(data.len() == 4, "Invalid length field value");
        let hexa = str::from_utf8(data).map_err(|err| {
            io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("Cannot read hexa length as UTF-8 ({})", err),
            )
        })?;
        u32::from_str_radix(hexa, 0x10).map_err(|err| {
            io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("Cannot parse hexa length ({})", err),
            )
        })
    }

    fn repair_adb_daemon() {
        if Self::start_adb_daemon() {
            thread::sleep(Duration::from_millis(Self::RETRY_DELAY_ADB_DAEMON_OK));
        } else {
            thread::sleep(Duration::from_millis(Self::RETRY_DELAY_ADB_DAEMON_KO));
        }
    }

    fn start_adb_daemon() -> bool {
        info!(target: TAG, "Restarting adb daemon");
        match process::Command::new("adb")
            .args(&["start-server"])
            .status() {
            Ok(exit_status) => {
                if exit_status.success() {
                    true
                } else {
                    error!(
                        target: TAG,
                        "Could not restart adb daemon (exited on error)"
                    );
                    false
                }
            }
            Err(err) => {
                error!(target: TAG, "Could not restart adb daemon: {}", err);
                false
            }
        }
    }

    fn to_string(data: &[u8]) -> io::Result<String> {
        let raw_content = data.to_vec();
        let content = String::from_utf8(raw_content);
        if let Ok(content) = content {
            Ok(content)
        } else {
            Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Track-devices string is not valid UTF-8",
            ))
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::cell::RefCell;
    use std::rc::Rc;

    #[test]
    fn test_read_valid_packet() {
        let mut buf = ByteBuffer::new(64);
        let raw = "00180123456789ABCDEF\tdevice\n".as_bytes();

        let mut cursor = io::Cursor::new(raw);
        buf.read_from(&mut cursor).unwrap();

        let packet = AdbMonitor::read_packet(&mut buf).unwrap().unwrap();
        assert_eq!("0123456789ABCDEF\tdevice\n", packet);
    }

    #[test]
    fn test_read_valid_packet_with_garbage() {
        let mut buf = ByteBuffer::new(64);
        let raw = "00180123456789ABCDEF\tdevice\ngarbage".as_bytes();

        let mut cursor = io::Cursor::new(raw);
        buf.read_from(&mut cursor).unwrap();

        let packet = AdbMonitor::read_packet(&mut buf).unwrap().unwrap();
        assert_eq!("0123456789ABCDEF\tdevice\n", packet);
    }

    #[test]
    fn test_read_short_packet() {
        let mut buf = ByteBuffer::new(64);
        let raw = "00180123456789ABCDEF\tdevi".as_bytes();

        let mut cursor = io::Cursor::new(raw);
        buf.read_from(&mut cursor).unwrap();

        let packet = AdbMonitor::read_packet(&mut buf).unwrap();
        assert!(packet.is_none());
    }

    #[test]
    fn test_handle_packet_device() {
        let serial = Rc::new(RefCell::new(None));
        let serial_clone = serial.clone();

        let monitor = AdbMonitor::new(Box::new(move |serial: &String| {
            serial_clone.replace(Some(serial.to_string()));
        }));
        monitor.handle_packet(&"0123456789ABCDEF\tdevice\n".to_string());

        assert_eq!("0123456789ABCDEF", serial.borrow().as_ref().unwrap());
    }

    #[test]
    fn test_handle_packet_offline() {
        let serial = Rc::new(RefCell::new(None));
        let serial_clone = serial.clone();

        let monitor = AdbMonitor::new(Box::new(move |serial: &String| {
            serial_clone.replace(Some(serial.to_string()));
        }));
        monitor.handle_packet(&"0123456789ABCDEF\toffline\n".to_string());

        assert!(serial.borrow().is_none());
    }
}
<|endoftext|>


<commit_before>use role_playing_game::*;

#[test]
fn test_reviving_dead_player() {
    let dead_player = Player {
        health: 0,
        mana: Some(0),
        level: 34,
    };
    let revived_player = dead_player
        .revive()
        .expect("reviving a dead player must return Some(player)");
    assert_eq!(revived_player.health, 100);
    assert_eq!(revived_player.mana, Some(100));
    assert_eq!(revived_player.level, dead_player.level);
}

#[test]
#[ignore]
fn test_reviving_alive_player() {
    let alive_player = Player {
        health: 1,
        mana: None,
        level: 8,
    };
    assert!(alive_player.revive().is_none());
}

#[test]
#[ignore]
fn test_cast_spell_with_enough_mana() {
    const HEALTH: u32 = 99;
    const MANA: u32 = 100;
    const LEVEL: u32 = 100;
    const MANA_COST: u32 = 3;

    let mut accomplished_wizard = Player {
        health: HEALTH,
        mana: Some(MANA),
        level: LEVEL,
    };

    assert_eq!(accomplished_wizard.cast_spell(MANA_COST), MANA_COST * 2);
    assert_eq!(accomplished_wizard.health, HEALTH);
    assert_eq!(accomplished_wizard.mana, Some(MANA - MANA_COST));
    assert_eq!(accomplished_wizard.level, LEVEL);
}

#[test]
#[ignore]
fn test_cast_spell_with_insufficient_mana() {
    let mut no_mana_wizard = Player {
        health: 56,
        mana: Some(2),
        level: 22,
    };

    // we want to clone so we can compare before-and-after effects of casting the spell,
    // but we don't want to introduce that concept to the student yet, so we have to do it manually
    let clone = Player { ..no_mana_wizard };

    assert_eq!(no_mana_wizard.cast_spell(3), 0);
    assert_eq!(no_mana_wizard.health, clone.health);
    assert_eq!(no_mana_wizard.mana, clone.mana);
    assert_eq!(no_mana_wizard.level, clone.level);
}

#[test]
#[ignore]
fn test_cast_spell_with_no_mana_pool() {
    const MANA_COST: u32 = 10;

    let mut underleveled_player = Player {
        health: 87,
        mana: None,
        level: 6,
    };

    let clone = Player {
        ..underleveled_player
    };

    assert_eq!(underleveled_player.cast_spell(MANA_COST), 0);
    assert_eq!(underleveled_player.health, clone.health - MANA_COST);
    assert_eq!(underleveled_player.mana, clone.mana);
    assert_eq!(underleveled_player.level, clone.level);
}
<commit_msg>Add test that forces handing of integer overflow. (#1312)<commit_after>use role_playing_game::*;

#[test]
fn test_reviving_dead_player() {
    let dead_player = Player {
        health: 0,
        mana: Some(0),
        level: 34,
    };
    let revived_player = dead_player
        .revive()
        .expect("reviving a dead player must return Some(player)");
    assert_eq!(revived_player.health, 100);
    assert_eq!(revived_player.mana, Some(100));
    assert_eq!(revived_player.level, dead_player.level);
}

#[test]
#[ignore]
fn test_reviving_alive_player() {
    let alive_player = Player {
        health: 1,
        mana: None,
        level: 8,
    };
    assert!(alive_player.revive().is_none());
}

#[test]
#[ignore]
fn test_cast_spell_with_enough_mana() {
    const HEALTH: u32 = 99;
    const MANA: u32 = 100;
    const LEVEL: u32 = 100;
    const MANA_COST: u32 = 3;

    let mut accomplished_wizard = Player {
        health: HEALTH,
        mana: Some(MANA),
        level: LEVEL,
    };

    assert_eq!(accomplished_wizard.cast_spell(MANA_COST), MANA_COST * 2);
    assert_eq!(accomplished_wizard.health, HEALTH);
    assert_eq!(accomplished_wizard.mana, Some(MANA - MANA_COST));
    assert_eq!(accomplished_wizard.level, LEVEL);
}

#[test]
#[ignore]
fn test_cast_spell_with_insufficient_mana() {
    let mut no_mana_wizard = Player {
        health: 56,
        mana: Some(2),
        level: 22,
    };

    // we want to clone so we can compare before-and-after effects of casting the spell,
    // but we don't want to introduce that concept to the student yet, so we have to do it manually
    let clone = Player { ..no_mana_wizard };

    assert_eq!(no_mana_wizard.cast_spell(3), 0);
    assert_eq!(no_mana_wizard.health, clone.health);
    assert_eq!(no_mana_wizard.mana, clone.mana);
    assert_eq!(no_mana_wizard.level, clone.level);
}

#[test]
#[ignore]
fn test_cast_spell_with_no_mana_pool() {
    const MANA_COST: u32 = 10;

    let mut underleveled_player = Player {
        health: 87,
        mana: None,
        level: 6,
    };

    let clone = Player {
        ..underleveled_player
    };

    assert_eq!(underleveled_player.cast_spell(MANA_COST), 0);
    assert_eq!(underleveled_player.health, clone.health - MANA_COST);
    assert_eq!(underleveled_player.mana, clone.mana);
    assert_eq!(underleveled_player.level, clone.level);
}

#[test]
#[ignore]
fn test_cast_large_spell_with_no_mana_pool() {
    const MANA_COST: u32 = 30;

    let mut underleveled_player = Player {
        health: 20,
        mana: None,
        level: 6,
    };

    assert_eq!(underleveled_player.cast_spell(MANA_COST), 0);
    assert_eq!(underleveled_player.health, 0);
    assert_eq!(underleveled_player.mana, None);
    assert_eq!(underleveled_player.level, 6);
}
<|endoftext|>


<commit_before>//! Unix pipe.
//!
//! See the [`new`] function for documentation.

use std::fs::File;
use std::io::{self, IoSlice, IoSliceMut, Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::process::{ChildStderr, ChildStdin, ChildStdout};

use crate::io_source::IoSource;
use crate::{event, Interest, Registry, Token};

/// Create a new non-blocking Unix pipe.
///
/// This is a wrapper around Unix's [`pipe(2)`] system call and can be used as
/// inter-process or thread communication channel.
///
/// This channel may be created before forking the process and then one end used
/// in each process, e.g. the parent process has the sending end to send command
/// to the child process.
///
/// [`pipe(2)`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html
///
/// # Events
///
/// The [`Sender`] can be registered with [`WRITABLE`] interest to receive
/// [writable events], the [`Receiver`] with [`READABLE`] interest. Once data is
/// written to the `Sender` the `Receiver` will receive an [readable event].
///
/// In addition to those events, events will also be generated if the other side
/// is dropped. To check if the `Sender` is dropped you'll need to check
/// [`is_read_closed`] on events for the `Receiver`, if it returns true the
/// `Sender` is dropped. On the `Sender` end check [`is_write_closed`], if it
/// returns true the `Receiver` was dropped. Also see the second example below.
///
/// [`WRITABLE`]: Interest::WRITABLE
/// [writable events]: event::Event::is_writable
/// [`READABLE`]: Interest::READABLE
/// [readable event]: event::Event::is_readable
/// [`is_read_closed`]: event::Event::is_read_closed
/// [`is_write_closed`]: event::Event::is_write_closed
///
/// # Deregistering
///
/// Both `Sender` and `Receiver` will deregister themselves when dropped,
/// **iff** the file descriptors are not duplicated (via [`dup(2)`]).
///
/// [`dup(2)`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html
///
/// # Examples
///
/// Simple example that writes data into the sending end and read it from the
/// receiving end.
///
/// ```
/// use std::io::{self, Read, Write};
///
/// use mio::{Poll, Events, Interest, Token};
/// use mio::unix::pipe;
///
/// // Unique tokens for the two ends of the channel.
/// const PIPE_RECV: Token = Token(0);
/// const PIPE_SEND: Token = Token(1);
///
/// # fn main() -> io::Result<()> {
/// // Create our `Poll` instance and the `Events` container.
/// let mut poll = Poll::new()?;
/// let mut events = Events::with_capacity(8);
///
/// // Create a new pipe.
/// let (mut sender, mut receiver) = pipe::new()?;
///
/// // Register both ends of the channel.
/// poll.registry().register(&mut receiver, PIPE_RECV, Interest::READABLE)?;
/// poll.registry().register(&mut sender, PIPE_SEND, Interest::WRITABLE)?;
///
/// const MSG: &[u8; 11] = b"Hello world";
///
/// loop {
///     poll.poll(&mut events, None)?;
///
///     for event in events.iter() {
///         match event.token() {
///             PIPE_SEND => sender.write(MSG)
///                 .and_then(|n| if n != MSG.len() {
///                         // We'll consider a short write an error in this
///                         // example. NOTE: we can't use `write_all` with
///                         // non-blocking I/O.
///                         Err(io::ErrorKind::WriteZero.into())
///                     } else {
///                         Ok(())
///                     })?,
///             PIPE_RECV => {
///                 let mut buf = [0; 11];
///                 let n = receiver.read(&mut buf)?;
///                 println!("received: {:?}", &buf[0..n]);
///                 assert_eq!(n, MSG.len());
///                 assert_eq!(&buf, &*MSG);
///                 return Ok(());
///             },
///             _ => unreachable!(),
///         }
///     }
/// }
/// # }
/// ```
///
/// Example that receives an event once the `Sender` is dropped.
///
/// ```
/// # use std::io;
/// #
/// # use mio::{Poll, Events, Interest, Token};
/// # use mio::unix::pipe;
/// #
/// # const PIPE_RECV: Token = Token(0);
/// # const PIPE_SEND: Token = Token(1);
/// #
/// # fn main() -> io::Result<()> {
/// // Same setup as in the example above.
/// let mut poll = Poll::new()?;
/// let mut events = Events::with_capacity(8);
///
/// let (mut sender, mut receiver) = pipe::new()?;
///
/// poll.registry().register(&mut receiver, PIPE_RECV, Interest::READABLE)?;
/// poll.registry().register(&mut sender, PIPE_SEND, Interest::WRITABLE)?;
///
/// // Drop the sender.
/// drop(sender);
///
/// poll.poll(&mut events, None)?;
///
/// for event in events.iter() {
///     match event.token() {
///         PIPE_RECV if event.is_read_closed() => {
///             // Detected that the sender was dropped.
///             println!("Sender dropped!");
///             return Ok(());
///         },
///         _ => unreachable!(),
///     }
/// }
/// # unreachable!();
/// # }
/// ```
pub fn new() -> io::Result<(Sender, Receiver)> {
    let mut fds: [RawFd; 2] = [-1, -1];

    #[cfg(any(
        target_os = "android",
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "linux",
        target_os = "netbsd",
        target_os = "openbsd",
    ))]
    unsafe {
        if libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC | libc::O_NONBLOCK) != 0 {
            return Err(io::Error::last_os_error());
        }
    }

    #[cfg(any(target_os = "ios", target_os = "macos", target_os = "solaris"))]
    unsafe {
        // For platforms that don't have `pipe2(2)` we need to manually set the
        // correct flags on the file descriptor.
        if libc::pipe(fds.as_mut_ptr()) != 0 {
            return Err(io::Error::last_os_error());
        }

        for fd in &fds {
            if libc::fcntl(*fd, libc::F_SETFL, libc::O_NONBLOCK) != 0
                || libc::fcntl(*fd, libc::F_SETFD, libc::FD_CLOEXEC) != 0
            {
                let err = io::Error::last_os_error();
                // Don't leak file descriptors. Can't handle error though.
                let _ = libc::close(fds[0]);
                let _ = libc::close(fds[1]);
                return Err(err);
            }
        }
    }

    #[cfg(not(any(
        target_os = "android",
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "linux",
        target_os = "netbsd",
        target_os = "openbsd",
        target_os = "ios",
        target_os = "macos",
        target_os = "solaris",
    )))]
    compile_error!("unsupported target for `mio::unix::pipe`");

    // Safety: we just initialised the `fds` above.
    let r = unsafe { Receiver::from_raw_fd(fds[0]) };
    let w = unsafe { Sender::from_raw_fd(fds[1]) };
    Ok((w, r))
}

/// Sending end of an Unix pipe.
///
/// See [`new`] for documentation, including examples.
#[derive(Debug)]
pub struct Sender {
    inner: IoSource<File>,
}

impl Sender {
    /// Set the `Sender` into or out of non-blocking mode.
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        set_nonblocking(self.inner.as_raw_fd(), nonblocking)
    }
}

impl event::Source for Sender {
    fn register(
        &mut self,
        registry: &Registry,
        token: Token,
        interests: Interest,
    ) -> io::Result<()> {
        self.inner.register(registry, token, interests)
    }

    fn reregister(
        &mut self,
        registry: &Registry,
        token: Token,
        interests: Interest,
    ) -> io::Result<()> {
        self.inner.reregister(registry, token, interests)
    }

    fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
        self.inner.deregister(registry)
    }
}

impl Write for Sender {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.inner.do_io(|sender| (&*sender).write(buf))
    }

    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        self.inner.do_io(|sender| (&*sender).write_vectored(bufs))
    }

    fn flush(&mut self) -> io::Result<()> {
        self.inner.do_io(|sender| (&*sender).flush())
    }
}

/// # Notes
///
/// The underlying pipe is **not** set to non-blocking.
impl From<ChildStdin> for Sender {
    fn from(stdin: ChildStdin) -> Sender {
        // Safety: `ChildStdin` is guaranteed to be a valid file descriptor.
        unsafe { Sender::from_raw_fd(stdin.into_raw_fd()) }
    }
}

impl FromRawFd for Sender {
    unsafe fn from_raw_fd(fd: RawFd) -> Sender {
        Sender {
            inner: IoSource::new(File::from_raw_fd(fd)),
        }
    }
}

impl AsRawFd for Sender {
    fn as_raw_fd(&self) -> RawFd {
        self.inner.as_raw_fd()
    }
}

impl IntoRawFd for Sender {
    fn into_raw_fd(self) -> RawFd {
        self.inner.into_inner().into_raw_fd()
    }
}

/// Receiving end of an Unix pipe.
///
/// See [`new`] for documentation, including examples.
#[derive(Debug)]
pub struct Receiver {
    inner: IoSource<File>,
}

impl Receiver {
    /// Set the `Receiver` into or out of non-blocking mode.
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        set_nonblocking(self.inner.as_raw_fd(), nonblocking)
    }
}

impl event::Source for Receiver {
    fn register(
        &mut self,
        registry: &Registry,
        token: Token,
        interests: Interest,
    ) -> io::Result<()> {
        self.inner.register(registry, token, interests)
    }

    fn reregister(
        &mut self,
        registry: &Registry,
        token: Token,
        interests: Interest,
    ) -> io::Result<()> {
        self.inner.reregister(registry, token, interests)
    }

    fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
        self.inner.deregister(registry)
    }
}

impl Read for Receiver {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner.do_io(|sender| (&*sender).read(buf))
    }

    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        self.inner.do_io(|sender| (&*sender).read_vectored(bufs))
    }
}

/// # Notes
///
/// The underlying pipe is **not** set to non-blocking.
impl From<ChildStdout> for Receiver {
    fn from(stdout: ChildStdout) -> Receiver {
        // Safety: `ChildStdout` is guaranteed to be a valid file descriptor.
        unsafe { Receiver::from_raw_fd(stdout.into_raw_fd()) }
    }
}

/// # Notes
///
/// The underlying pipe is **not** set to non-blocking.
impl From<ChildStderr> for Receiver {
    fn from(stderr: ChildStderr) -> Receiver {
        // Safety: `ChildStderr` is guaranteed to be a valid file descriptor.
        unsafe { Receiver::from_raw_fd(stderr.into_raw_fd()) }
    }
}

impl FromRawFd for Receiver {
    unsafe fn from_raw_fd(fd: RawFd) -> Receiver {
        Receiver {
            inner: IoSource::new(File::from_raw_fd(fd)),
        }
    }
}

impl AsRawFd for Receiver {
    fn as_raw_fd(&self) -> RawFd {
        self.inner.as_raw_fd()
    }
}

impl IntoRawFd for Receiver {
    fn into_raw_fd(self) -> RawFd {
        self.inner.into_inner().into_raw_fd()
    }
}

fn set_nonblocking(fd: RawFd, nonblocking: bool) -> io::Result<()> {
    let value = nonblocking as libc::c_int;
    if unsafe { libc::ioctl(fd, libc::FIONBIO, &value) } == -1 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}
<commit_msg>Implement Read/Write for &pipe::Sender/&pipe::Receiver<commit_after>//! Unix pipe.
//!
//! See the [`new`] function for documentation.

use std::fs::File;
use std::io::{self, IoSlice, IoSliceMut, Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::process::{ChildStderr, ChildStdin, ChildStdout};

use crate::io_source::IoSource;
use crate::{event, Interest, Registry, Token};

/// Create a new non-blocking Unix pipe.
///
/// This is a wrapper around Unix's [`pipe(2)`] system call and can be used as
/// inter-process or thread communication channel.
///
/// This channel may be created before forking the process and then one end used
/// in each process, e.g. the parent process has the sending end to send command
/// to the child process.
///
/// [`pipe(2)`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html
///
/// # Events
///
/// The [`Sender`] can be registered with [`WRITABLE`] interest to receive
/// [writable events], the [`Receiver`] with [`READABLE`] interest. Once data is
/// written to the `Sender` the `Receiver` will receive an [readable event].
///
/// In addition to those events, events will also be generated if the other side
/// is dropped. To check if the `Sender` is dropped you'll need to check
/// [`is_read_closed`] on events for the `Receiver`, if it returns true the
/// `Sender` is dropped. On the `Sender` end check [`is_write_closed`], if it
/// returns true the `Receiver` was dropped. Also see the second example below.
///
/// [`WRITABLE`]: Interest::WRITABLE
/// [writable events]: event::Event::is_writable
/// [`READABLE`]: Interest::READABLE
/// [readable event]: event::Event::is_readable
/// [`is_read_closed`]: event::Event::is_read_closed
/// [`is_write_closed`]: event::Event::is_write_closed
///
/// # Deregistering
///
/// Both `Sender` and `Receiver` will deregister themselves when dropped,
/// **iff** the file descriptors are not duplicated (via [`dup(2)`]).
///
/// [`dup(2)`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html
///
/// # Examples
///
/// Simple example that writes data into the sending end and read it from the
/// receiving end.
///
/// ```
/// use std::io::{self, Read, Write};
///
/// use mio::{Poll, Events, Interest, Token};
/// use mio::unix::pipe;
///
/// // Unique tokens for the two ends of the channel.
/// const PIPE_RECV: Token = Token(0);
/// const PIPE_SEND: Token = Token(1);
///
/// # fn main() -> io::Result<()> {
/// // Create our `Poll` instance and the `Events` container.
/// let mut poll = Poll::new()?;
/// let mut events = Events::with_capacity(8);
///
/// // Create a new pipe.
/// let (mut sender, mut receiver) = pipe::new()?;
///
/// // Register both ends of the channel.
/// poll.registry().register(&mut receiver, PIPE_RECV, Interest::READABLE)?;
/// poll.registry().register(&mut sender, PIPE_SEND, Interest::WRITABLE)?;
///
/// const MSG: &[u8; 11] = b"Hello world";
///
/// loop {
///     poll.poll(&mut events, None)?;
///
///     for event in events.iter() {
///         match event.token() {
///             PIPE_SEND => sender.write(MSG)
///                 .and_then(|n| if n != MSG.len() {
///                         // We'll consider a short write an error in this
///                         // example. NOTE: we can't use `write_all` with
///                         // non-blocking I/O.
///                         Err(io::ErrorKind::WriteZero.into())
///                     } else {
///                         Ok(())
///                     })?,
///             PIPE_RECV => {
///                 let mut buf = [0; 11];
///                 let n = receiver.read(&mut buf)?;
///                 println!("received: {:?}", &buf[0..n]);
///                 assert_eq!(n, MSG.len());
///                 assert_eq!(&buf, &*MSG);
///                 return Ok(());
///             },
///             _ => unreachable!(),
///         }
///     }
/// }
/// # }
/// ```
///
/// Example that receives an event once the `Sender` is dropped.
///
/// ```
/// # use std::io;
/// #
/// # use mio::{Poll, Events, Interest, Token};
/// # use mio::unix::pipe;
/// #
/// # const PIPE_RECV: Token = Token(0);
/// # const PIPE_SEND: Token = Token(1);
/// #
/// # fn main() -> io::Result<()> {
/// // Same setup as in the example above.
/// let mut poll = Poll::new()?;
/// let mut events = Events::with_capacity(8);
///
/// let (mut sender, mut receiver) = pipe::new()?;
///
/// poll.registry().register(&mut receiver, PIPE_RECV, Interest::READABLE)?;
/// poll.registry().register(&mut sender, PIPE_SEND, Interest::WRITABLE)?;
///
/// // Drop the sender.
/// drop(sender);
///
/// poll.poll(&mut events, None)?;
///
/// for event in events.iter() {
///     match event.token() {
///         PIPE_RECV if event.is_read_closed() => {
///             // Detected that the sender was dropped.
///             println!("Sender dropped!");
///             return Ok(());
///         },
///         _ => unreachable!(),
///     }
/// }
/// # unreachable!();
/// # }
/// ```
pub fn new() -> io::Result<(Sender, Receiver)> {
    let mut fds: [RawFd; 2] = [-1, -1];

    #[cfg(any(
        target_os = "android",
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "linux",
        target_os = "netbsd",
        target_os = "openbsd",
    ))]
    unsafe {
        if libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC | libc::O_NONBLOCK) != 0 {
            return Err(io::Error::last_os_error());
        }
    }

    #[cfg(any(target_os = "ios", target_os = "macos", target_os = "solaris"))]
    unsafe {
        // For platforms that don't have `pipe2(2)` we need to manually set the
        // correct flags on the file descriptor.
        if libc::pipe(fds.as_mut_ptr()) != 0 {
            return Err(io::Error::last_os_error());
        }

        for fd in &fds {
            if libc::fcntl(*fd, libc::F_SETFL, libc::O_NONBLOCK) != 0
                || libc::fcntl(*fd, libc::F_SETFD, libc::FD_CLOEXEC) != 0
            {
                let err = io::Error::last_os_error();
                // Don't leak file descriptors. Can't handle error though.
                let _ = libc::close(fds[0]);
                let _ = libc::close(fds[1]);
                return Err(err);
            }
        }
    }

    #[cfg(not(any(
        target_os = "android",
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "linux",
        target_os = "netbsd",
        target_os = "openbsd",
        target_os = "ios",
        target_os = "macos",
        target_os = "solaris",
    )))]
    compile_error!("unsupported target for `mio::unix::pipe`");

    // Safety: we just initialised the `fds` above.
    let r = unsafe { Receiver::from_raw_fd(fds[0]) };
    let w = unsafe { Sender::from_raw_fd(fds[1]) };
    Ok((w, r))
}

/// Sending end of an Unix pipe.
///
/// See [`new`] for documentation, including examples.
#[derive(Debug)]
pub struct Sender {
    inner: IoSource<File>,
}

impl Sender {
    /// Set the `Sender` into or out of non-blocking mode.
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        set_nonblocking(self.inner.as_raw_fd(), nonblocking)
    }
}

impl event::Source for Sender {
    fn register(
        &mut self,
        registry: &Registry,
        token: Token,
        interests: Interest,
    ) -> io::Result<()> {
        self.inner.register(registry, token, interests)
    }

    fn reregister(
        &mut self,
        registry: &Registry,
        token: Token,
        interests: Interest,
    ) -> io::Result<()> {
        self.inner.reregister(registry, token, interests)
    }

    fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
        self.inner.deregister(registry)
    }
}

impl Write for Sender {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.inner.do_io(|sender| (&*sender).write(buf))
    }

    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        self.inner.do_io(|sender| (&*sender).write_vectored(bufs))
    }

    fn flush(&mut self) -> io::Result<()> {
        self.inner.do_io(|sender| (&*sender).flush())
    }
}

impl Write for &Sender {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.inner.do_io(|sender| (&*sender).write(buf))
    }

    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        self.inner.do_io(|sender| (&*sender).write_vectored(bufs))
    }

    fn flush(&mut self) -> io::Result<()> {
        self.inner.do_io(|sender| (&*sender).flush())
    }
}

/// # Notes
///
/// The underlying pipe is **not** set to non-blocking.
impl From<ChildStdin> for Sender {
    fn from(stdin: ChildStdin) -> Sender {
        // Safety: `ChildStdin` is guaranteed to be a valid file descriptor.
        unsafe { Sender::from_raw_fd(stdin.into_raw_fd()) }
    }
}

impl FromRawFd for Sender {
    unsafe fn from_raw_fd(fd: RawFd) -> Sender {
        Sender {
            inner: IoSource::new(File::from_raw_fd(fd)),
        }
    }
}

impl AsRawFd for Sender {
    fn as_raw_fd(&self) -> RawFd {
        self.inner.as_raw_fd()
    }
}

impl IntoRawFd for Sender {
    fn into_raw_fd(self) -> RawFd {
        self.inner.into_inner().into_raw_fd()
    }
}

/// Receiving end of an Unix pipe.
///
/// See [`new`] for documentation, including examples.
#[derive(Debug)]
pub struct Receiver {
    inner: IoSource<File>,
}

impl Receiver {
    /// Set the `Receiver` into or out of non-blocking mode.
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        set_nonblocking(self.inner.as_raw_fd(), nonblocking)
    }
}

impl event::Source for Receiver {
    fn register(
        &mut self,
        registry: &Registry,
        token: Token,
        interests: Interest,
    ) -> io::Result<()> {
        self.inner.register(registry, token, interests)
    }

    fn reregister(
        &mut self,
        registry: &Registry,
        token: Token,
        interests: Interest,
    ) -> io::Result<()> {
        self.inner.reregister(registry, token, interests)
    }

    fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
        self.inner.deregister(registry)
    }
}

impl Read for Receiver {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner.do_io(|sender| (&*sender).read(buf))
    }

    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        self.inner.do_io(|sender| (&*sender).read_vectored(bufs))
    }
}

impl Read for &Receiver {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner.do_io(|sender| (&*sender).read(buf))
    }

    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        self.inner.do_io(|sender| (&*sender).read_vectored(bufs))
    }
}

/// # Notes
///
/// The underlying pipe is **not** set to non-blocking.
impl From<ChildStdout> for Receiver {
    fn from(stdout: ChildStdout) -> Receiver {
        // Safety: `ChildStdout` is guaranteed to be a valid file descriptor.
        unsafe { Receiver::from_raw_fd(stdout.into_raw_fd()) }
    }
}

/// # Notes
///
/// The underlying pipe is **not** set to non-blocking.
impl From<ChildStderr> for Receiver {
    fn from(stderr: ChildStderr) -> Receiver {
        // Safety: `ChildStderr` is guaranteed to be a valid file descriptor.
        unsafe { Receiver::from_raw_fd(stderr.into_raw_fd()) }
    }
}

impl FromRawFd for Receiver {
    unsafe fn from_raw_fd(fd: RawFd) -> Receiver {
        Receiver {
            inner: IoSource::new(File::from_raw_fd(fd)),
        }
    }
}

impl AsRawFd for Receiver {
    fn as_raw_fd(&self) -> RawFd {
        self.inner.as_raw_fd()
    }
}

impl IntoRawFd for Receiver {
    fn into_raw_fd(self) -> RawFd {
        self.inner.into_inner().into_raw_fd()
    }
}

fn set_nonblocking(fd: RawFd, nonblocking: bool) -> io::Result<()> {
    let value = nonblocking as libc::c_int;
    if unsafe { libc::ioctl(fd, libc::FIONBIO, &value) } == -1 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::{
    fs::File,
    path::{Path, PathBuf},
};

use crate::{background_jobs::Environment, uploaders::Uploader};
use reqwest::header;
use swirl::PerformError;

/// Create CSV dumps of the public information in the database, wrap them in a
/// tarball and upload to S3.
#[swirl::background_job]
pub fn dump_db(
    env: &Environment,
    database_url: String,
    target_name: String,
) -> Result<(), PerformError> {
    let directory = DumpDirectory::create()?;

    println!("Begin exporting database");
    directory.populate(&database_url)?;

    println!("Creating tarball");
    let tarball = DumpTarball::create(&directory.export_dir)?;

    println!("Uploading tarball");
    let size = tarball.upload(&target_name, &env.uploader)?;
    println!("Database dump uploaded {} bytes to {}.", size, &target_name);
    Ok(())
}

/// Manage the export directory.
///
/// Create the directory, populate it with the psql scripts and CSV dumps, and
/// make sure it gets deleted again even in the case of an error.
#[derive(Debug)]
pub struct DumpDirectory {
    pub timestamp: chrono::DateTime<chrono::Utc>,
    pub export_dir: PathBuf,
}

impl DumpDirectory {
    pub fn create() -> Result<Self, PerformError> {
        let timestamp = chrono::Utc::now();
        let timestamp_str = timestamp.format("%Y-%m-%d-%H%M%S").to_string();
        let export_dir = std::env::temp_dir().join("dump-db").join(timestamp_str);
        std::fs::create_dir_all(&export_dir)?;
        Ok(Self {
            timestamp,
            export_dir,
        })
    }

    pub fn populate(&self, database_url: &str) -> Result<(), PerformError> {
        self.add_readme()?;
        self.add_metadata()?;
        self.dump_schema(database_url)?;
        self.dump_db(database_url)
    }

    fn add_readme(&self) -> Result<(), PerformError> {
        use std::io::Write;

        let mut readme = File::create(self.export_dir.join("README.md"))?;
        readme.write_all(include_bytes!("dump_db/readme_for_tarball.md"))?;
        Ok(())
    }

    fn add_metadata(&self) -> Result<(), PerformError> {
        #[derive(Serialize)]
        struct Metadata<'a> {
            timestamp: &'a chrono::DateTime<chrono::Utc>,
            crates_io_commit: String,
        }
        let metadata = Metadata {
            timestamp: &self.timestamp,
            crates_io_commit: dotenv::var("HEROKU_SLUG_COMMIT")
                .unwrap_or_else(|_| "unknown".to_owned()),
        };
        let file = File::create(self.export_dir.join("metadata.json"))?;
        serde_json::to_writer_pretty(file, &metadata)?;
        Ok(())
    }

    pub fn dump_schema(&self, database_url: &str) -> Result<(), PerformError> {
        let schema_sql = File::create(self.export_dir.join("schema.sql"))?;
        let status = std::process::Command::new("pg_dump")
            .arg("--schema-only")
            .arg("--no-owner")
            .arg("--no-acl")
            .arg(database_url)
            .stdout(schema_sql)
            .spawn()?
            .wait()?;
        if !status.success() {
            return Err("pg_dump did not finish successfully.".into());
        }
        Ok(())
    }

    pub fn dump_db(&self, database_url: &str) -> Result<(), PerformError> {
        let export_script = self.export_dir.join("export.sql");
        let import_script = self.export_dir.join("import.sql");
        gen_scripts::gen_scripts(&export_script, &import_script)?;
        std::fs::create_dir(self.export_dir.join("data"))?;
        run_psql(&export_script, database_url)
    }
}

impl Drop for DumpDirectory {
    fn drop(&mut self) {
        std::fs::remove_dir_all(&self.export_dir).unwrap();
    }
}

pub fn run_psql(script: &Path, database_url: &str) -> Result<(), PerformError> {
    let psql_script = File::open(&script)?;
    let psql = std::process::Command::new("psql")
        .arg(database_url)
        .current_dir(script.parent().unwrap())
        .stdin(psql_script)
        .stdout(std::process::Stdio::null())
        .stderr(std::process::Stdio::piped())
        .spawn()?;
    let output = psql.wait_with_output()?;
    let stderr = String::from_utf8_lossy(&output.stderr);
    if stderr.contains("ERROR") {
        return Err(format!("Error while executing psql: {}", stderr).into());
    }
    if !output.status.success() {
        return Err("psql did not finish successfully.".into());
    }
    Ok(())
}

/// Manage the tarball of the database dump.
///
/// Create the tarball, upload it to S3, and make sure it gets deleted.
struct DumpTarball {
    tarball_path: PathBuf,
}

impl DumpTarball {
    fn create(export_dir: &Path) -> Result<Self, PerformError> {
        let tarball_path = export_dir.with_extension("tar.gz");
        let tarfile = File::create(&tarball_path)?;
        let result = Self { tarball_path };
        let encoder = flate2::write::GzEncoder::new(tarfile, flate2::Compression::default());
        let mut archive = tar::Builder::new(encoder);
        archive.append_dir_all(export_dir.file_name().unwrap(), &export_dir)?;
        Ok(result)
    }

    fn upload(&self, target_name: &str, uploader: &Uploader) -> Result<u64, PerformError> {
        let client = reqwest::blocking::Client::new();
        let tarfile = File::open(&self.tarball_path)?;
        let content_length = tarfile.metadata()?.len();
        // TODO Figure out the correct content type.
        uploader.upload(
            &client,
            target_name,
            tarfile,
            content_length,
            "application/gzip",
            header::HeaderMap::new(),
        )?;
        Ok(content_length)
    }
}

impl Drop for DumpTarball {
    fn drop(&mut self) {
        std::fs::remove_file(&self.tarball_path).unwrap();
    }
}

mod configuration;
mod gen_scripts;
<commit_msg>Topologically sort db-dump.tar.gz<commit_after>use std::{
    fs::{self, File},
    path::{Path, PathBuf},
};

use self::configuration::VisibilityConfig;
use crate::{background_jobs::Environment, uploaders::Uploader};
use reqwest::header;
use swirl::PerformError;

/// Create CSV dumps of the public information in the database, wrap them in a
/// tarball and upload to S3.
#[swirl::background_job]
pub fn dump_db(
    env: &Environment,
    database_url: String,
    target_name: String,
) -> Result<(), PerformError> {
    let directory = DumpDirectory::create()?;

    println!("Begin exporting database");
    directory.populate(&database_url)?;

    println!("Creating tarball");
    let tarball = DumpTarball::create(&directory.export_dir)?;

    println!("Uploading tarball");
    let size = tarball.upload(&target_name, &env.uploader)?;
    println!("Database dump uploaded {} bytes to {}.", size, &target_name);
    Ok(())
}

/// Manage the export directory.
///
/// Create the directory, populate it with the psql scripts and CSV dumps, and
/// make sure it gets deleted again even in the case of an error.
#[derive(Debug)]
pub struct DumpDirectory {
    pub timestamp: chrono::DateTime<chrono::Utc>,
    pub export_dir: PathBuf,
}

impl DumpDirectory {
    pub fn create() -> Result<Self, PerformError> {
        let timestamp = chrono::Utc::now();
        let timestamp_str = timestamp.format("%Y-%m-%d-%H%M%S").to_string();
        let export_dir = std::env::temp_dir().join("dump-db").join(timestamp_str);
        std::fs::create_dir_all(&export_dir)?;
        Ok(Self {
            timestamp,
            export_dir,
        })
    }

    pub fn populate(&self, database_url: &str) -> Result<(), PerformError> {
        self.add_readme()?;
        self.add_metadata()?;
        self.dump_schema(database_url)?;
        self.dump_db(database_url)
    }

    fn add_readme(&self) -> Result<(), PerformError> {
        use std::io::Write;

        let mut readme = File::create(self.export_dir.join("README.md"))?;
        readme.write_all(include_bytes!("dump_db/readme_for_tarball.md"))?;
        Ok(())
    }

    fn add_metadata(&self) -> Result<(), PerformError> {
        #[derive(Serialize)]
        struct Metadata<'a> {
            timestamp: &'a chrono::DateTime<chrono::Utc>,
            crates_io_commit: String,
        }
        let metadata = Metadata {
            timestamp: &self.timestamp,
            crates_io_commit: dotenv::var("HEROKU_SLUG_COMMIT")
                .unwrap_or_else(|_| "unknown".to_owned()),
        };
        let file = File::create(self.export_dir.join("metadata.json"))?;
        serde_json::to_writer_pretty(file, &metadata)?;
        Ok(())
    }

    pub fn dump_schema(&self, database_url: &str) -> Result<(), PerformError> {
        let schema_sql = File::create(self.export_dir.join("schema.sql"))?;
        let status = std::process::Command::new("pg_dump")
            .arg("--schema-only")
            .arg("--no-owner")
            .arg("--no-acl")
            .arg(database_url)
            .stdout(schema_sql)
            .spawn()?
            .wait()?;
        if !status.success() {
            return Err("pg_dump did not finish successfully.".into());
        }
        Ok(())
    }

    pub fn dump_db(&self, database_url: &str) -> Result<(), PerformError> {
        let export_script = self.export_dir.join("export.sql");
        let import_script = self.export_dir.join("import.sql");
        gen_scripts::gen_scripts(&export_script, &import_script)?;
        std::fs::create_dir(self.export_dir.join("data"))?;
        run_psql(&export_script, database_url)
    }
}

impl Drop for DumpDirectory {
    fn drop(&mut self) {
        std::fs::remove_dir_all(&self.export_dir).unwrap();
    }
}

pub fn run_psql(script: &Path, database_url: &str) -> Result<(), PerformError> {
    let psql_script = File::open(&script)?;
    let psql = std::process::Command::new("psql")
        .arg(database_url)
        .current_dir(script.parent().unwrap())
        .stdin(psql_script)
        .stdout(std::process::Stdio::null())
        .stderr(std::process::Stdio::piped())
        .spawn()?;
    let output = psql.wait_with_output()?;
    let stderr = String::from_utf8_lossy(&output.stderr);
    if stderr.contains("ERROR") {
        return Err(format!("Error while executing psql: {}", stderr).into());
    }
    if !output.status.success() {
        return Err("psql did not finish successfully.".into());
    }
    Ok(())
}

/// Manage the tarball of the database dump.
///
/// Create the tarball, upload it to S3, and make sure it gets deleted.
struct DumpTarball {
    tarball_path: PathBuf,
}

impl DumpTarball {
    fn create(export_dir: &Path) -> Result<Self, PerformError> {
        let tarball_path = export_dir.with_extension("tar.gz");
        let tarfile = File::create(&tarball_path)?;
        let result = Self { tarball_path };
        let encoder = flate2::write::GzEncoder::new(tarfile, flate2::Compression::default());

        let mut archive = tar::Builder::new(encoder);
        let tar_top_dir = PathBuf::from(export_dir.file_name().unwrap());
        archive.append_dir(&tar_top_dir, export_dir)?;

        // Append readme, metadata, schemas.
        for entry in fs::read_dir(export_dir)? {
            let entry = entry?;
            let file_type = entry.file_type()?;
            if file_type.is_file() {
                let name_in_tar = tar_top_dir.join(entry.file_name());
                archive.append_path_with_name(entry.path(), name_in_tar)?;
            }
        }

        // Append topologically sorted tables to make it possible to pipeline
        // importing with gz extraction.
        archive.append_dir(tar_top_dir.join("data"), export_dir.join("data"))?;
        for table in VisibilityConfig::get().topological_sort() {
            let csv_path = export_dir.join("data").join(table).with_extension("csv");
            if csv_path.exists() {
                let name_in_tar = tar_top_dir.join("data").join(table).with_extension("csv");
                archive.append_path_with_name(csv_path, name_in_tar)?;
            }
        }

        Ok(result)
    }

    fn upload(&self, target_name: &str, uploader: &Uploader) -> Result<u64, PerformError> {
        let client = reqwest::blocking::Client::new();
        let tarfile = File::open(&self.tarball_path)?;
        let content_length = tarfile.metadata()?.len();
        // TODO Figure out the correct content type.
        uploader.upload(
            &client,
            target_name,
            tarfile,
            content_length,
            "application/gzip",
            header::HeaderMap::new(),
        )?;
        Ok(content_length)
    }
}

impl Drop for DumpTarball {
    fn drop(&mut self) {
        std::fs::remove_file(&self.tarball_path).unwrap();
    }
}

mod configuration;
mod gen_scripts;
<|endoftext|>


<commit_before><commit_msg>Rename StiffDiag into Diag and remove nonlinear (use EOM instead)<commit_after><|endoftext|>


<commit_before>use crate::config::DEFAULT_BEACON_NODE;
use clap::{App, Arg};

pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
    App::new("validator_client")
        .visible_aliases(&["v", "vc", "validator"])
        .setting(clap::AppSettings::ColoredHelp)
        .about(
            "When connected to a beacon node, performs the duties of a staked \
                validator (e.g., proposing blocks and attestations).",
        )
        // This argument is deprecated, use `--beacon-nodes` instead.
        .arg(
            Arg::with_name("beacon-node")
                .long("beacon-node")
                .value_name("NETWORK_ADDRESS")
                .help("Deprecated. Use --beacon-nodes.")
                .takes_value(true)
                .conflicts_with("beacon-nodes"),
        )
        .arg(
            Arg::with_name("beacon-nodes")
                .long("beacon-nodes")
                .value_name("NETWORK_ADDRESSES")
                .help("Comma-separated addresses to one or more beacon node HTTP APIs")
                .default_value(&DEFAULT_BEACON_NODE)
                .takes_value(true),
        )
        // This argument is deprecated, use `--beacon-nodes` instead.
        .arg(
            Arg::with_name("server")
                .long("server")
                .value_name("NETWORK_ADDRESS")
                .help("Deprecated. Use --beacon-nodes.")
                .takes_value(true)
                .conflicts_with_all(&["beacon-node", "beacon-nodes"]),
        )
        .arg(
            Arg::with_name("validators-dir")
                .long("validators-dir")
                .value_name("VALIDATORS_DIR")
                .help(
                    "The directory which contains the validator keystores, deposit data for \
                    each validator along with the common slashing protection database \
                    and the validator_definitions.yml"
                )
                .takes_value(true)
                .conflicts_with("datadir")
        )
        .arg(
            Arg::with_name("secrets-dir")
                .long("secrets-dir")
                .value_name("SECRETS_DIRECTORY")
                .help(
                    "The directory which contains the password to unlock the validator \
                    voting keypairs. Each password should be contained in a file where the \
                    name is the 0x-prefixed hex representation of the validators voting public \
                    key. Defaults to ~/.lighthouse/{network}/secrets.",
                )
                .takes_value(true)
                .conflicts_with("datadir")
        )
        .arg(
            Arg::with_name("delete-lockfiles")
            .long("delete-lockfiles")
            .help(
                "DEPRECATED. This flag does nothing and will be removed in a future release."
            )
        )
        .arg(
            Arg::with_name("init-slashing-protection")
                .long("init-slashing-protection")
                .help(
                    "If present, do not require the slashing protection database to exist before \
                     running. You SHOULD NOT use this flag unless you're certain that a new \
                     slashing protection database is required. Usually, your database \
                     will have been initialized when you imported your validator keys. If you \
                     misplace your database and then run with this flag you risk being slashed."
                )
        )
        .arg(
            Arg::with_name("disable-auto-discover")
            .long("disable-auto-discover")
            .help(
                "If present, do not attempt to discover new validators in the validators-dir. Validators \
                will need to be manually added to the validator_definitions.yml file."
            )
        )
        .arg(
            Arg::with_name("allow-unsynced")
                .long("allow-unsynced")
                .help(
                    "If present, the validator client will still poll for duties if the beacon
                      node is not synced.",
                ),
        )
        // This overwrites the graffiti configured in the beacon node.
        .arg(
            Arg::with_name("graffiti")
                .long("graffiti")
                .help("Specify your custom graffiti to be included in blocks.")
                .value_name("GRAFFITI")
                .takes_value(true)
        )
        /* REST API related arguments */
        .arg(
            Arg::with_name("http")
                .long("http")
                .help("Enable the RESTful HTTP API server. Disabled by default.")
                .takes_value(false),
        )
        /*
         * Note: there is purposefully no `--http-address` flag provided.
         *
         * The HTTP server is **not** encrypted (i.e., not HTTPS) and therefore it is unsafe to
         * publish on a public network.
         *
         * We restrict the user to `127.0.0.1` and they must provide some other transport-layer
         * encryption (e.g., SSH tunnels).
         */
        .arg(
            Arg::with_name("http-port")
                .long("http-port")
                .value_name("PORT")
                .help("Set the listen TCP port for the RESTful HTTP API server. This server does **not** \
                provide encryption and is completely unsuitable to expose to a public network. \
                We do not provide a --http-address flag and restrict the user to listening on \
                127.0.0.1. For access via the Internet, apply a transport-layer security like \
                a HTTPS reverse-proxy or SSH tunnelling.")
                .default_value("5062")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("http-allow-origin")
                .long("http-allow-origin")
                .value_name("ORIGIN")
                .help("Set the value of the Access-Control-Allow-Origin response HTTP header. \
                    Use * to allow any origin (not recommended in production). \
                    If no value is supplied, the CORS allowed origin is set to the listen \
                    address of this server (e.g., http://localhost:5062).")
                .takes_value(true),
        )
        /* Prometheus metrics HTTP server related arguments */
        .arg(
            Arg::with_name("metrics")
                .long("metrics")
                .help("Enable the Prometheus metrics HTTP server. Disabled by default.")
                .takes_value(false),
        )
        .arg(
            Arg::with_name("metrics-address")
                .long("metrics-address")
                .value_name("ADDRESS")
                .help("Set the listen address for the Prometheus metrics HTTP server.")
                .default_value("127.0.0.1")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("metrics-port")
                .long("metrics-port")
                .value_name("PORT")
                .help("Set the listen TCP port for the Prometheus metrics HTTP server.")
                .default_value("5064")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("metrics-allow-origin")
                .long("metrics-allow-origin")
                .value_name("ORIGIN")
                .help("Set the value of the Access-Control-Allow-Origin response HTTP header. \
                    Use * to allow any origin (not recommended in production). \
                    If no value is supplied, the CORS allowed origin is set to the listen \
                    address of this server (e.g., http://localhost:5064).")
                .takes_value(true),
        )
}
<commit_msg>Remove default beacon node value from clap (#2121)<commit_after>use clap::{App, Arg};

pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
    App::new("validator_client")
        .visible_aliases(&["v", "vc", "validator"])
        .setting(clap::AppSettings::ColoredHelp)
        .about(
            "When connected to a beacon node, performs the duties of a staked \
                validator (e.g., proposing blocks and attestations).",
        )
        // This argument is deprecated, use `--beacon-nodes` instead.
        .arg(
            Arg::with_name("beacon-node")
                .long("beacon-node")
                .value_name("NETWORK_ADDRESS")
                .help("Deprecated. Use --beacon-nodes.")
                .takes_value(true)
                .conflicts_with("beacon-nodes"),
        )
        .arg(
            Arg::with_name("beacon-nodes")
                .long("beacon-nodes")
                .value_name("NETWORK_ADDRESSES")
                .help("Comma-separated addresses to one or more beacon node HTTP APIs. \
                       Default is http://localhost:5052."
                )
                .takes_value(true),
        )
        // This argument is deprecated, use `--beacon-nodes` instead.
        .arg(
            Arg::with_name("server")
                .long("server")
                .value_name("NETWORK_ADDRESS")
                .help("Deprecated. Use --beacon-nodes.")
                .takes_value(true)
                .conflicts_with_all(&["beacon-node", "beacon-nodes"]),
        )
        .arg(
            Arg::with_name("validators-dir")
                .long("validators-dir")
                .value_name("VALIDATORS_DIR")
                .help(
                    "The directory which contains the validator keystores, deposit data for \
                    each validator along with the common slashing protection database \
                    and the validator_definitions.yml"
                )
                .takes_value(true)
                .conflicts_with("datadir")
        )
        .arg(
            Arg::with_name("secrets-dir")
                .long("secrets-dir")
                .value_name("SECRETS_DIRECTORY")
                .help(
                    "The directory which contains the password to unlock the validator \
                    voting keypairs. Each password should be contained in a file where the \
                    name is the 0x-prefixed hex representation of the validators voting public \
                    key. Defaults to ~/.lighthouse/{network}/secrets.",
                )
                .takes_value(true)
                .conflicts_with("datadir")
        )
        .arg(
            Arg::with_name("delete-lockfiles")
            .long("delete-lockfiles")
            .help(
                "DEPRECATED. This flag does nothing and will be removed in a future release."
            )
        )
        .arg(
            Arg::with_name("init-slashing-protection")
                .long("init-slashing-protection")
                .help(
                    "If present, do not require the slashing protection database to exist before \
                     running. You SHOULD NOT use this flag unless you're certain that a new \
                     slashing protection database is required. Usually, your database \
                     will have been initialized when you imported your validator keys. If you \
                     misplace your database and then run with this flag you risk being slashed."
                )
        )
        .arg(
            Arg::with_name("disable-auto-discover")
            .long("disable-auto-discover")
            .help(
                "If present, do not attempt to discover new validators in the validators-dir. Validators \
                will need to be manually added to the validator_definitions.yml file."
            )
        )
        .arg(
            Arg::with_name("allow-unsynced")
                .long("allow-unsynced")
                .help(
                    "If present, the validator client will still poll for duties if the beacon
                      node is not synced.",
                ),
        )
        // This overwrites the graffiti configured in the beacon node.
        .arg(
            Arg::with_name("graffiti")
                .long("graffiti")
                .help("Specify your custom graffiti to be included in blocks.")
                .value_name("GRAFFITI")
                .takes_value(true)
        )
        /* REST API related arguments */
        .arg(
            Arg::with_name("http")
                .long("http")
                .help("Enable the RESTful HTTP API server. Disabled by default.")
                .takes_value(false),
        )
        /*
         * Note: there is purposefully no `--http-address` flag provided.
         *
         * The HTTP server is **not** encrypted (i.e., not HTTPS) and therefore it is unsafe to
         * publish on a public network.
         *
         * We restrict the user to `127.0.0.1` and they must provide some other transport-layer
         * encryption (e.g., SSH tunnels).
         */
        .arg(
            Arg::with_name("http-port")
                .long("http-port")
                .value_name("PORT")
                .help("Set the listen TCP port for the RESTful HTTP API server. This server does **not** \
                provide encryption and is completely unsuitable to expose to a public network. \
                We do not provide a --http-address flag and restrict the user to listening on \
                127.0.0.1. For access via the Internet, apply a transport-layer security like \
                a HTTPS reverse-proxy or SSH tunnelling.")
                .default_value("5062")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("http-allow-origin")
                .long("http-allow-origin")
                .value_name("ORIGIN")
                .help("Set the value of the Access-Control-Allow-Origin response HTTP header. \
                    Use * to allow any origin (not recommended in production). \
                    If no value is supplied, the CORS allowed origin is set to the listen \
                    address of this server (e.g., http://localhost:5062).")
                .takes_value(true),
        )
        /* Prometheus metrics HTTP server related arguments */
        .arg(
            Arg::with_name("metrics")
                .long("metrics")
                .help("Enable the Prometheus metrics HTTP server. Disabled by default.")
                .takes_value(false),
        )
        .arg(
            Arg::with_name("metrics-address")
                .long("metrics-address")
                .value_name("ADDRESS")
                .help("Set the listen address for the Prometheus metrics HTTP server.")
                .default_value("127.0.0.1")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("metrics-port")
                .long("metrics-port")
                .value_name("PORT")
                .help("Set the listen TCP port for the Prometheus metrics HTTP server.")
                .default_value("5064")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("metrics-allow-origin")
                .long("metrics-allow-origin")
                .value_name("ORIGIN")
                .help("Set the value of the Access-Control-Allow-Origin response HTTP header. \
                    Use * to allow any origin (not recommended in production). \
                    If no value is supplied, the CORS allowed origin is set to the listen \
                    address of this server (e.g., http://localhost:5064).")
                .takes_value(true),
        )
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! A bin with a decorative frame and optional label

use glib::translate::ToGlibPtr;
use ffi;

/// Frame — A bin with a decorative frame and optional label
struct_Widget!(Frame);

impl Frame {
    pub fn new(label: Option<&str>) -> Option<Frame> {
        let tmp_pointer = unsafe {
            ffi::gtk_frame_new(label.to_glib_none().0)
        };
        check_pointer!(tmp_pointer, Frame)
    }
}

impl_drop!(Frame);
impl_TraitWidget!(Frame);

impl ::FrameTrait for Frame {}
impl ::ContainerTrait for Frame {}
impl ::BinTrait for Frame {}
<commit_msg>Remove struct Frame<commit_after><|endoftext|>