<commit_before>#![allow(dead_code, unused_must_use, unused_variables, unused_imports)]

use mio;
use mio::{Poll,Ready};
use mio::unix::UnixReady;
use std::fmt;
use std::str;
use std::net::SocketAddr;
use std::rc::Rc;
use std::cell::RefCell;
use slab::{Entry,VacantEntry};
use time::{precise_time_ns,SteadyTime,Duration};

use sozu_command::messages::{OrderMessage,OrderMessageAnswer,LoadBalancingParams};

#[macro_use] pub mod metrics;
pub mod pool;
pub mod buffer_queue;
pub mod socket;
pub mod trie;
pub mod protocol;
pub mod http;
pub mod backends;
pub mod retry;
pub mod load_balancing;

#[cfg(feature = "splice")]
mod splice;

pub mod tcp;
pub mod proxy;

#[cfg(feature = "use-openssl")]
pub mod https_openssl;

pub mod https_rustls;

use mio::Token;

use self::retry::RetryPolicy;

pub type AppId = String;

#[derive(Debug,Clone,Copy,PartialEq)]
pub enum Protocol {
  HTTP,
  HTTPS,
  TCP,
  HTTPListen,
  HTTPSListen,
  TCPListen,
  Channel,
  Metrics,
}

#[derive(Debug,Clone,Default)]
pub struct CloseResult {
  pub tokens:   Vec<Token>,
  pub backends: Vec<(String, SocketAddr)>,
}

pub trait ProxyClient {
  fn protocol(&self)  -> Protocol;
  fn ready(&mut self) -> ClientResult;
  fn process_events(&mut self, token: Token, events: Ready);
  fn close(&mut self, poll: &mut Poll) -> CloseResult;
  fn close_backend(&mut self, token: Token, poll: &mut Poll) -> Option<(String, SocketAddr)>;
}

#[derive(Clone,Copy,Debug,PartialEq)]
pub enum BackendConnectionStatus {
  NotConnected,
  Connecting,
  Connected,
}

#[derive(Debug,PartialEq)]
pub enum BackendConnectAction {
  New,
  Reuse,
  Replace,
}

#[derive(Debug,PartialEq)]
pub enum AcceptError {
  IoError,
  TooManyClients,
  WouldBlock,
}

use self::proxy::{ClientToken,ListenToken,ListenPortState};
pub trait ProxyConfiguration<Client> {
  fn connect_to_backend(&mut self, event_loop: &mut Poll, client: &mut Client,
    back_token: Token) ->Result<BackendConnectAction,ConnectionError>;
  fn notify(&mut self, event_loop: &mut Poll, message: OrderMessage) -> OrderMessageAnswer;
  fn accept(&mut self, token: ListenToken, event_loop: &mut Poll, client_token: Token)
    -> Result<(Rc<RefCell<Client>>, bool), AcceptError>;
  fn accept_flush(&mut self) -> usize;
  fn close_backend(&mut self, app_id: String, addr: &SocketAddr);
  fn listen_port_state(&self, port: &u16) -> ListenPortState;
}

#[derive(Debug,PartialEq,Eq)]
pub enum RequiredEvents {
  FrontReadBackNone,
  FrontWriteBackNone,
  FrontReadWriteBackNone,
  FrontNoneBackNone,
  FrontReadBackRead,
  FrontWriteBackRead,
  FrontReadWriteBackRead,
  FrontNoneBackRead,
  FrontReadBackWrite,
  FrontWriteBackWrite,
  FrontReadWriteBackWrite,
  FrontNoneBackWrite,
  FrontReadBackReadWrite,
  FrontWriteBackReadWrite,
  FrontReadWriteBackReadWrite,
  FrontNoneBackReadWrite,
}

impl RequiredEvents {

  pub fn front_readable(&self) -> bool {
    match *self {
      RequiredEvents::FrontReadBackNone
      | RequiredEvents:: FrontReadWriteBackNone
      | RequiredEvents:: FrontReadBackRead
      | RequiredEvents:: FrontReadWriteBackRead
      | RequiredEvents:: FrontReadBackWrite
      | RequiredEvents:: FrontReadWriteBackWrite
      | RequiredEvents:: FrontReadBackReadWrite
      | RequiredEvents:: FrontReadWriteBackReadWrite => true,
      _ => false
    }
  }

  pub fn front_writable(&self) -> bool {
    match *self {
        RequiredEvents::FrontWriteBackNone
        | RequiredEvents::FrontReadWriteBackNone
        | RequiredEvents::FrontWriteBackRead
        | RequiredEvents::FrontReadWriteBackRead
        | RequiredEvents::FrontWriteBackWrite
        | RequiredEvents::FrontReadWriteBackWrite
        | RequiredEvents::FrontWriteBackReadWrite
        | RequiredEvents::FrontReadWriteBackReadWrite => true,
        _ => false
    }
  }

  pub fn back_readable(&self) -> bool {
    match *self {
        RequiredEvents::FrontReadBackRead
        | RequiredEvents::FrontWriteBackRead
        | RequiredEvents::FrontReadWriteBackRead
        | RequiredEvents::FrontNoneBackRead
        | RequiredEvents::FrontReadBackReadWrite
        | RequiredEvents::FrontWriteBackReadWrite
        | RequiredEvents::FrontReadWriteBackReadWrite
        | RequiredEvents::FrontNoneBackReadWrite => true,
        _ => false
    }
  }

  pub fn back_writable(&self) -> bool {
    match *self {
        RequiredEvents::FrontReadBackWrite
        | RequiredEvents::FrontWriteBackWrite
        | RequiredEvents::FrontReadWriteBackWrite
        | RequiredEvents::FrontNoneBackWrite
        | RequiredEvents::FrontReadBackReadWrite
        | RequiredEvents::FrontWriteBackReadWrite
        | RequiredEvents::FrontReadWriteBackReadWrite
        | RequiredEvents::FrontNoneBackReadWrite => true,
        _ => false
    }
  }
}

#[derive(Debug,PartialEq,Eq)]
pub enum ClientResult {
  CloseClient,
  CloseBackend(Option<Token>),
  ReconnectBackend(Option<Token>, Option<Token>),
  Continue,
  ConnectBackend
}

#[derive(Debug,PartialEq,Eq)]
pub enum ConnectionError {
  NoHostGiven,
  NoRequestLineGiven,
  InvalidHost,
  HostNotFound,
  NoBackendAvailable,
  ToBeDefined,
  HttpsRedirect
}

#[derive(Debug,PartialEq,Eq)]
pub enum SocketType {
  Listener,
  FrontClient
}

#[derive(Debug,PartialEq,Eq)]
pub enum BackendStatus {
  Normal,
  Closing,
  Closed,
}

#[derive(Debug,PartialEq,Eq)]
pub struct Backend {
  pub sticky_id:                 Option<String>,
  pub backend_id:                String,
  pub address:                   SocketAddr,
  pub status:                    BackendStatus,
  pub retry_policy:              retry::RetryPolicyWrapper,
  pub active_connections:        usize,
  pub failures:                  usize,
  pub load_balancing_parameters: Option<LoadBalancingParams>,
}

impl Backend {
  pub fn new(backend_id: &str, addr: SocketAddr, sticky_id: Option<String>, load_balancing_parameters: Option<LoadBalancingParams>) -> Backend {
    let desired_policy = retry::ExponentialBackoffPolicy::new(10);
    Backend {
      sticky_id:          sticky_id,
      backend_id:         backend_id.to_string(),
      address:            addr,
      status:             BackendStatus::Normal,
      retry_policy:       desired_policy.into(),
      active_connections: 0,
      failures:           0,
      load_balancing_parameters,
    }
  }

  pub fn set_closing(&mut self) {
    self.status = BackendStatus::Closing;
  }

  pub fn retry_policy(&mut self) -> &mut retry::RetryPolicyWrapper {
    &mut self.retry_policy
  }

  pub fn can_open(&self) -> bool {
    if let Some(action) = self.retry_policy.can_try() {
      self.status == BackendStatus::Normal && action == retry::RetryAction::OKAY
    } else {
      false
    }
  }

  pub fn inc_connections(&mut self) -> Option<usize> {
    if self.status == BackendStatus::Normal {
      self.active_connections += 1;
      Some(self.active_connections)
    } else {
      None
    }
  }

  pub fn dec_connections(&mut self) -> Option<usize> {
    if self.active_connections == 0 {
      self.status = BackendStatus::Closed;
      return None;
    }

    match self.status {
      BackendStatus::Normal => {
        self.active_connections -= 1;
        Some(self.active_connections)
      }
      BackendStatus::Closed  => None,
      BackendStatus::Closing => {
        self.active_connections -= 1;
        if self.active_connections == 0 {
          self.status = BackendStatus::Closed;
          None
        } else {
          Some(self.active_connections)
        }
      },
    }
  }

  pub fn try_connect(&mut self) -> Result<mio::tcp::TcpStream, ConnectionError> {
    if self.status != BackendStatus::Normal {
      return Err(ConnectionError::NoBackendAvailable);
    }

    //FIXME: what happens if the connect() call fails with EINPROGRESS?
    let conn = mio::tcp::TcpStream::connect(&self.address).map_err(|_| ConnectionError::NoBackendAvailable);
    if conn.is_ok() {
      //self.retry_policy.succeed();
      self.inc_connections();
    } else {
      self.retry_policy.fail();
      self.failures += 1;
    }

    conn
  }
}

pub struct Readiness {
  pub front_interest:  UnixReady,
  pub back_interest:   UnixReady,
  pub front_readiness: UnixReady,
  pub back_readiness:  UnixReady,
}

impl Readiness {
  pub fn new() -> Readiness {
    Readiness {
      front_interest:  UnixReady::from(Ready::empty()),
      back_interest:   UnixReady::from(Ready::empty()),
      front_readiness: UnixReady::from(Ready::empty()),
      back_readiness:  UnixReady::from(Ready::empty()),
    }
  }

  pub fn reset(&mut self) {
    self.front_interest  = UnixReady::from(Ready::empty());
    self.back_interest   = UnixReady::from(Ready::empty());
    self.front_readiness = UnixReady::from(Ready::empty());
    self.back_readiness  = UnixReady::from(Ready::empty());
  }
}

pub fn display_unix_ready(s: &mut [u8], readiness: UnixReady) {
  if readiness.is_readable() {
    s[0] = b'R';
  }
  if readiness.is_writable() {
    s[1] = b'W';
  }
  if readiness.is_error() {
    s[2] = b'E';
  }
  if readiness.is_hup() {
    s[3] = b'H';
  }
}

pub fn unix_ready_to_string(readiness: UnixReady) -> String {
  let s = &mut [b'-'; 4];
  display_unix_ready(s, readiness);
  String::from_utf8(s.to_vec()).unwrap()
}

impl fmt::Debug for Readiness {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

    let front_i = &mut [b'-'; 4];
    let front_r = &mut [b'-'; 4];
    let back_i  = &mut [b'-'; 4];
    let back_r  = &mut [b'-'; 4];
    let front   = &mut [b'-'; 4];
    let back    = &mut [b'-'; 4];

    display_unix_ready(front_i, self.front_interest);
    display_unix_ready(front_r, self.front_readiness);
    display_unix_ready(back_i, self.back_interest);
    display_unix_ready(back_r, self.back_readiness);
    display_unix_ready(front, self.front_interest & self.front_readiness);
    display_unix_ready(back, self.back_interest & self.back_readiness);

    write!(f, "Readiness {{ front_interest: {}, front_readiness: {}, back_interest: {}, back_readiness: {} }} | front: {}, back: {}",
      str::from_utf8(front_i).unwrap(),
      str::from_utf8(front_r).unwrap(),
      str::from_utf8(back_i).unwrap(),
      str::from_utf8(back_r).unwrap(),
      str::from_utf8(front).unwrap(),
      str::from_utf8(back).unwrap())

  }
}

#[derive(Clone,Debug)]
pub struct SessionMetrics {
  /// date at which we started handling that request
  pub start:        Option<SteadyTime>,
  /// time actually spent handling the request
  pub service_time: Duration,
  /// bytes received by the frontend
  pub bin:          usize,
  /// bytes sent by the frontend
  pub bout:         usize,

  /// date at which we started working on the request
  pub service_start: Option<SteadyTime>,

  pub backend_id:    Option<String>,
  pub backend_start: Option<SteadyTime>,
  pub backend_stop:  Option<SteadyTime>,
  pub backend_bin:   usize,
  pub backend_bout:  usize,
}

impl SessionMetrics {
  pub fn new() -> SessionMetrics {
    SessionMetrics {
      start:         Some(SteadyTime::now()),
      service_time:  Duration::seconds(0),
      bin:           0,
      bout:          0,
      service_start: None,
      backend_id:    None,
      backend_start: None,
      backend_stop:  None,
      backend_bin:   0,
      backend_bout:  0,
    }
  }

  pub fn reset(&mut self) {
    self.start         = None;
    self.service_time  = Duration::seconds(0);
    self.bin           = 0;
    self.bout          = 0;
    self.service_start = None;
    self.backend_id    = None;
    self.backend_start = None;
    self.backend_stop  = None;
    self.backend_bin   = 0;
    self.backend_bout  = 0;
  }

  pub fn start(&mut self) {
    if self.start.is_none() {
      self.start = Some(SteadyTime::now());
    }
  }

  pub fn service_start(&mut self) {
    if self.start.is_none() {
      self.start = Some(SteadyTime::now());
    }

    self.service_start = Some(SteadyTime::now());
  }

  pub fn service_stop(&mut self) {
    if self.service_start.is_some() {
      let start = self.service_start.take().unwrap();
      let duration = SteadyTime::now() - start;
      self.service_time = self.service_time + duration;
    }
  }

  pub fn service_time(&self) -> Duration {
    match self.service_start {
      Some(start) => {
        let last_duration = SteadyTime::now() - start;
        self.service_time + last_duration
      },
      None        => self.service_time,
    }
  }

  pub fn response_time(&self) -> Duration {
    match self.start {
      Some(start) => SteadyTime::now() - start,
      None        => Duration::seconds(0),
    }
  }

  pub fn backend_start(&mut self) {
    self.backend_start = Some(SteadyTime::now());
  }

  pub fn backend_stop(&mut self) {
    self.backend_stop = Some(SteadyTime::now());
  }

  pub fn backend_response_time(&self) -> Option<Duration> {
    match (self.backend_start, self.backend_stop) {
      (Some(start), Some(end)) => {
        Some(end - start)
      },
      (Some(start), None) => Some(SteadyTime::now() - start),
      _ => None
    }
  }
}

pub struct LogDuration(Duration);

impl fmt::Display for LogDuration {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    let secs = self.0.num_seconds();
    if secs >= 10 {
      return write!(f, "{}s", secs);
    }

    let ms = self.0.num_milliseconds();

    if ms < 10 {
      if let Some(us) = self.0.num_microseconds() {
        if us >= 10 {
          return write!(f, "{}μs", us);
        }

        if let Some(ns) = self.0.num_nanoseconds() {
          return write!(f, "{}ns", ns);
        }
      }
    }

    write!(f, "{}ms", ms)
  }
}

<commit_msg>a backend is not closed if there are no active connections<commit_after>#![allow(dead_code, unused_must_use, unused_variables, unused_imports)]

use mio;
use mio::{Poll,Ready};
use mio::unix::UnixReady;
use std::fmt;
use std::str;
use std::net::SocketAddr;
use std::rc::Rc;
use std::cell::RefCell;
use slab::{Entry,VacantEntry};
use time::{precise_time_ns,SteadyTime,Duration};

use sozu_command::messages::{OrderMessage,OrderMessageAnswer,LoadBalancingParams};

#[macro_use] pub mod metrics;
pub mod pool;
pub mod buffer_queue;
pub mod socket;
pub mod trie;
pub mod protocol;
pub mod http;
pub mod backends;
pub mod retry;
pub mod load_balancing;

#[cfg(feature = "splice")]
mod splice;

pub mod tcp;
pub mod proxy;

#[cfg(feature = "use-openssl")]
pub mod https_openssl;

pub mod https_rustls;

use mio::Token;

use self::retry::RetryPolicy;

pub type AppId = String;

#[derive(Debug,Clone,Copy,PartialEq)]
pub enum Protocol {
  HTTP,
  HTTPS,
  TCP,
  HTTPListen,
  HTTPSListen,
  TCPListen,
  Channel,
  Metrics,
}

#[derive(Debug,Clone,Default)]
pub struct CloseResult {
  pub tokens:   Vec<Token>,
  pub backends: Vec<(String, SocketAddr)>,
}

pub trait ProxyClient {
  fn protocol(&self)  -> Protocol;
  fn ready(&mut self) -> ClientResult;
  fn process_events(&mut self, token: Token, events: Ready);
  fn close(&mut self, poll: &mut Poll) -> CloseResult;
  fn close_backend(&mut self, token: Token, poll: &mut Poll) -> Option<(String, SocketAddr)>;
}

#[derive(Clone,Copy,Debug,PartialEq)]
pub enum BackendConnectionStatus {
  NotConnected,
  Connecting,
  Connected,
}

#[derive(Debug,PartialEq)]
pub enum BackendConnectAction {
  New,
  Reuse,
  Replace,
}

#[derive(Debug,PartialEq)]
pub enum AcceptError {
  IoError,
  TooManyClients,
  WouldBlock,
}

use self::proxy::{ClientToken,ListenToken,ListenPortState};
pub trait ProxyConfiguration<Client> {
  fn connect_to_backend(&mut self, event_loop: &mut Poll, client: &mut Client,
    back_token: Token) ->Result<BackendConnectAction,ConnectionError>;
  fn notify(&mut self, event_loop: &mut Poll, message: OrderMessage) -> OrderMessageAnswer;
  fn accept(&mut self, token: ListenToken, event_loop: &mut Poll, client_token: Token)
    -> Result<(Rc<RefCell<Client>>, bool), AcceptError>;
  fn accept_flush(&mut self) -> usize;
  fn close_backend(&mut self, app_id: String, addr: &SocketAddr);
  fn listen_port_state(&self, port: &u16) -> ListenPortState;
}

#[derive(Debug,PartialEq,Eq)]
pub enum RequiredEvents {
  FrontReadBackNone,
  FrontWriteBackNone,
  FrontReadWriteBackNone,
  FrontNoneBackNone,
  FrontReadBackRead,
  FrontWriteBackRead,
  FrontReadWriteBackRead,
  FrontNoneBackRead,
  FrontReadBackWrite,
  FrontWriteBackWrite,
  FrontReadWriteBackWrite,
  FrontNoneBackWrite,
  FrontReadBackReadWrite,
  FrontWriteBackReadWrite,
  FrontReadWriteBackReadWrite,
  FrontNoneBackReadWrite,
}

impl RequiredEvents {

  pub fn front_readable(&self) -> bool {
    match *self {
      RequiredEvents::FrontReadBackNone
      | RequiredEvents:: FrontReadWriteBackNone
      | RequiredEvents:: FrontReadBackRead
      | RequiredEvents:: FrontReadWriteBackRead
      | RequiredEvents:: FrontReadBackWrite
      | RequiredEvents:: FrontReadWriteBackWrite
      | RequiredEvents:: FrontReadBackReadWrite
      | RequiredEvents:: FrontReadWriteBackReadWrite => true,
      _ => false
    }
  }

  pub fn front_writable(&self) -> bool {
    match *self {
        RequiredEvents::FrontWriteBackNone
        | RequiredEvents::FrontReadWriteBackNone
        | RequiredEvents::FrontWriteBackRead
        | RequiredEvents::FrontReadWriteBackRead
        | RequiredEvents::FrontWriteBackWrite
        | RequiredEvents::FrontReadWriteBackWrite
        | RequiredEvents::FrontWriteBackReadWrite
        | RequiredEvents::FrontReadWriteBackReadWrite => true,
        _ => false
    }
  }

  pub fn back_readable(&self) -> bool {
    match *self {
        RequiredEvents::FrontReadBackRead
        | RequiredEvents::FrontWriteBackRead
        | RequiredEvents::FrontReadWriteBackRead
        | RequiredEvents::FrontNoneBackRead
        | RequiredEvents::FrontReadBackReadWrite
        | RequiredEvents::FrontWriteBackReadWrite
        | RequiredEvents::FrontReadWriteBackReadWrite
        | RequiredEvents::FrontNoneBackReadWrite => true,
        _ => false
    }
  }

  pub fn back_writable(&self) -> bool {
    match *self {
        RequiredEvents::FrontReadBackWrite
        | RequiredEvents::FrontWriteBackWrite
        | RequiredEvents::FrontReadWriteBackWrite
        | RequiredEvents::FrontNoneBackWrite
        | RequiredEvents::FrontReadBackReadWrite
        | RequiredEvents::FrontWriteBackReadWrite
        | RequiredEvents::FrontReadWriteBackReadWrite
        | RequiredEvents::FrontNoneBackReadWrite => true,
        _ => false
    }
  }
}

#[derive(Debug,PartialEq,Eq)]
pub enum ClientResult {
  CloseClient,
  CloseBackend(Option<Token>),
  ReconnectBackend(Option<Token>, Option<Token>),
  Continue,
  ConnectBackend
}

#[derive(Debug,PartialEq,Eq)]
pub enum ConnectionError {
  NoHostGiven,
  NoRequestLineGiven,
  InvalidHost,
  HostNotFound,
  NoBackendAvailable,
  ToBeDefined,
  HttpsRedirect
}

#[derive(Debug,PartialEq,Eq)]
pub enum SocketType {
  Listener,
  FrontClient
}

#[derive(Debug,PartialEq,Eq)]
pub enum BackendStatus {
  Normal,
  Closing,
  Closed,
}

#[derive(Debug,PartialEq,Eq)]
pub struct Backend {
  pub sticky_id:                 Option<String>,
  pub backend_id:                String,
  pub address:                   SocketAddr,
  pub status:                    BackendStatus,
  pub retry_policy:              retry::RetryPolicyWrapper,
  pub active_connections:        usize,
  pub failures:                  usize,
  pub load_balancing_parameters: Option<LoadBalancingParams>,
}

impl Backend {
  pub fn new(backend_id: &str, addr: SocketAddr, sticky_id: Option<String>, load_balancing_parameters: Option<LoadBalancingParams>) -> Backend {
    let desired_policy = retry::ExponentialBackoffPolicy::new(10);
    Backend {
      sticky_id:          sticky_id,
      backend_id:         backend_id.to_string(),
      address:            addr,
      status:             BackendStatus::Normal,
      retry_policy:       desired_policy.into(),
      active_connections: 0,
      failures:           0,
      load_balancing_parameters,
    }
  }

  pub fn set_closing(&mut self) {
    self.status = BackendStatus::Closing;
  }

  pub fn retry_policy(&mut self) -> &mut retry::RetryPolicyWrapper {
    &mut self.retry_policy
  }

  pub fn can_open(&self) -> bool {
    if let Some(action) = self.retry_policy.can_try() {
      self.status == BackendStatus::Normal && action == retry::RetryAction::OKAY
    } else {
      false
    }
  }

  pub fn inc_connections(&mut self) -> Option<usize> {
    if self.status == BackendStatus::Normal {
      self.active_connections += 1;
      Some(self.active_connections)
    } else {
      None
    }
  }

  pub fn dec_connections(&mut self) -> Option<usize> {
    match self.status {
      BackendStatus::Normal => {
        if self.active_connections > 0 {
          self.active_connections -= 1;
        }
        Some(self.active_connections)
      }
      BackendStatus::Closed  => None,
      BackendStatus::Closing => {
        if self.active_connections > 0 {
          self.active_connections -= 1;
        }
        if self.active_connections == 0 {
          self.status = BackendStatus::Closed;
          None
        } else {
          Some(self.active_connections)
        }
      },
    }
  }

  pub fn try_connect(&mut self) -> Result<mio::tcp::TcpStream, ConnectionError> {
    if self.status != BackendStatus::Normal {
      return Err(ConnectionError::NoBackendAvailable);
    }

    //FIXME: what happens if the connect() call fails with EINPROGRESS?
    let conn = mio::tcp::TcpStream::connect(&self.address).map_err(|_| ConnectionError::NoBackendAvailable);
    if conn.is_ok() {
      //self.retry_policy.succeed();
      self.inc_connections();
    } else {
      self.retry_policy.fail();
      self.failures += 1;
    }

    conn
  }
}

pub struct Readiness {
  pub front_interest:  UnixReady,
  pub back_interest:   UnixReady,
  pub front_readiness: UnixReady,
  pub back_readiness:  UnixReady,
}

impl Readiness {
  pub fn new() -> Readiness {
    Readiness {
      front_interest:  UnixReady::from(Ready::empty()),
      back_interest:   UnixReady::from(Ready::empty()),
      front_readiness: UnixReady::from(Ready::empty()),
      back_readiness:  UnixReady::from(Ready::empty()),
    }
  }

  pub fn reset(&mut self) {
    self.front_interest  = UnixReady::from(Ready::empty());
    self.back_interest   = UnixReady::from(Ready::empty());
    self.front_readiness = UnixReady::from(Ready::empty());
    self.back_readiness  = UnixReady::from(Ready::empty());
  }
}

pub fn display_unix_ready(s: &mut [u8], readiness: UnixReady) {
  if readiness.is_readable() {
    s[0] = b'R';
  }
  if readiness.is_writable() {
    s[1] = b'W';
  }
  if readiness.is_error() {
    s[2] = b'E';
  }
  if readiness.is_hup() {
    s[3] = b'H';
  }
}

pub fn unix_ready_to_string(readiness: UnixReady) -> String {
  let s = &mut [b'-'; 4];
  display_unix_ready(s, readiness);
  String::from_utf8(s.to_vec()).unwrap()
}

impl fmt::Debug for Readiness {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

    let front_i = &mut [b'-'; 4];
    let front_r = &mut [b'-'; 4];
    let back_i  = &mut [b'-'; 4];
    let back_r  = &mut [b'-'; 4];
    let front   = &mut [b'-'; 4];
    let back    = &mut [b'-'; 4];

    display_unix_ready(front_i, self.front_interest);
    display_unix_ready(front_r, self.front_readiness);
    display_unix_ready(back_i, self.back_interest);
    display_unix_ready(back_r, self.back_readiness);
    display_unix_ready(front, self.front_interest & self.front_readiness);
    display_unix_ready(back, self.back_interest & self.back_readiness);

    write!(f, "Readiness {{ front_interest: {}, front_readiness: {}, back_interest: {}, back_readiness: {} }} | front: {}, back: {}",
      str::from_utf8(front_i).unwrap(),
      str::from_utf8(front_r).unwrap(),
      str::from_utf8(back_i).unwrap(),
      str::from_utf8(back_r).unwrap(),
      str::from_utf8(front).unwrap(),
      str::from_utf8(back).unwrap())

  }
}

#[derive(Clone,Debug)]
pub struct SessionMetrics {
  /// date at which we started handling that request
  pub start:        Option<SteadyTime>,
  /// time actually spent handling the request
  pub service_time: Duration,
  /// bytes received by the frontend
  pub bin:          usize,
  /// bytes sent by the frontend
  pub bout:         usize,

  /// date at which we started working on the request
  pub service_start: Option<SteadyTime>,

  pub backend_id:    Option<String>,
  pub backend_start: Option<SteadyTime>,
  pub backend_stop:  Option<SteadyTime>,
  pub backend_bin:   usize,
  pub backend_bout:  usize,
}

impl SessionMetrics {
  pub fn new() -> SessionMetrics {
    SessionMetrics {
      start:         Some(SteadyTime::now()),
      service_time:  Duration::seconds(0),
      bin:           0,
      bout:          0,
      service_start: None,
      backend_id:    None,
      backend_start: None,
      backend_stop:  None,
      backend_bin:   0,
      backend_bout:  0,
    }
  }

  pub fn reset(&mut self) {
    self.start         = None;
    self.service_time  = Duration::seconds(0);
    self.bin           = 0;
    self.bout          = 0;
    self.service_start = None;
    self.backend_id    = None;
    self.backend_start = None;
    self.backend_stop  = None;
    self.backend_bin   = 0;
    self.backend_bout  = 0;
  }

  pub fn start(&mut self) {
    if self.start.is_none() {
      self.start = Some(SteadyTime::now());
    }
  }

  pub fn service_start(&mut self) {
    if self.start.is_none() {
      self.start = Some(SteadyTime::now());
    }

    self.service_start = Some(SteadyTime::now());
  }

  pub fn service_stop(&mut self) {
    if self.service_start.is_some() {
      let start = self.service_start.take().unwrap();
      let duration = SteadyTime::now() - start;
      self.service_time = self.service_time + duration;
    }
  }

  pub fn service_time(&self) -> Duration {
    match self.service_start {
      Some(start) => {
        let last_duration = SteadyTime::now() - start;
        self.service_time + last_duration
      },
      None        => self.service_time,
    }
  }

  pub fn response_time(&self) -> Duration {
    match self.start {
      Some(start) => SteadyTime::now() - start,
      None        => Duration::seconds(0),
    }
  }

  pub fn backend_start(&mut self) {
    self.backend_start = Some(SteadyTime::now());
  }

  pub fn backend_stop(&mut self) {
    self.backend_stop = Some(SteadyTime::now());
  }

  pub fn backend_response_time(&self) -> Option<Duration> {
    match (self.backend_start, self.backend_stop) {
      (Some(start), Some(end)) => {
        Some(end - start)
      },
      (Some(start), None) => Some(SteadyTime::now() - start),
      _ => None
    }
  }
}

pub struct LogDuration(Duration);

impl fmt::Display for LogDuration {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    let secs = self.0.num_seconds();
    if secs >= 10 {
      return write!(f, "{}s", secs);
    }

    let ms = self.0.num_milliseconds();

    if ms < 10 {
      if let Some(us) = self.0.num_microseconds() {
        if us >= 10 {
          return write!(f, "{}μs", us);
        }

        if let Some(ns) = self.0.num_nanoseconds() {
          return write!(f, "{}ns", ns);
        }
      }
    }

    write!(f, "{}ms", ms)
  }
}

<|endoftext|>


<commit_before>use geom::size::Size2D;

pub trait ShareContext {
    // Creates a new context for GL object sharing.
    static fn new(size: Size2D<int>) -> self;

    // Flushes the context.
    fn flush(&self);

    // Returns the platform-specific ID that can be passed to other processes to access the shared
    // resources.
    fn id() -> int;
}

<commit_msg>Update for language changes<commit_after>use geom::size::Size2D;

pub trait ShareContext {
    // Creates a new context for GL object sharing.
    static fn new(size: Size2D<int>) -> Self;

    // Flushes the context.
    fn flush(&self);

    // Returns the platform-specific ID that can be passed to other processes to access the shared
    // resources.
    fn id() -> int;
}

<|endoftext|>


<commit_before>use std;

type id = libc::intptr_t;
type Class = libc::intptr_t;
type IMP = *u8;
type SEL = libc::intptr_t;
type Ivar = libc::intptr_t;

const nil : id = 0 as id;

extern mod objc {
    fn class_addMethod(cls : Class,
                       name : SEL,
                       imp : IMP,
                       types : *libc::c_char) -> bool;
    fn class_addIvar(cls : Class,
                     name : *libc::c_char,
                     size : libc::size_t,
                     alignment: u8,
		     types: *libc::c_char) -> bool;
    fn object_setInstanceVariable(obj : id,
                                  name : *libc::c_char,
                                  value : *libc::c_void);
    fn object_getInstanceVariable(obj : id,
                                  name : *libc::c_char,
                                  outValue : **libc::c_void);
    fn objc_allocateClassPair(superclass : Class,
                              name : *libc::c_char,
                              extraBytes : libc::size_t) -> Class;
    fn objc_getClass(name : *libc::c_char) -> id;
    fn objc_msgSend(theReceiver : id, theSelector : SEL) -> id;
    fn objc_registerClassPair(cls : Class);
    fn sel_registerName(name : *libc::c_char) -> SEL;
}

#[test]
fn test_nsapp() {
    let klass = str::as_c_str(~"NSApplication", |s|
        objc::objc_getClass(s)
    );

    let sel = str::as_c_str(~"sharedApplication", |s|
        objc::sel_registerName(s)
    );

    let nsapp = objc::objc_msgSend(klass, sel);

    io::println(#fmt(~"nsapp: %d", (nsapp as int)));
}

#[test]
fn test_custom_obj() {
    extern fn MyObject_doSomething(this : id, _sel : SEL) -> id {
        io::println("doSomething");
        ret this;
    }

    let NSObject = str::as_c_str(~"NSObject", |s|
        objc::objc_getClass(s)
    );
    let MyObject = str::as_c_str(~"MyObject", |s|
        objc::objc_allocateClassPair(NSObject, s, 0 as libc::size_t)
    );
    let doSomething = str::as_c_str(~"doSomething", |s|
        objc::sel_registerName(s)
    );
    let _ = str::as_c_str(~"@@:", |types|
        objc::class_addMethod(MyObject, doSomething, MyObject_doSomething,
                              types)
    );
    objc::objc_registerClassPair(MyObject);

    let alloc = str::as_c_str(~"alloc", |s| objc::sel_registerName(s));
    let init = str::as_c_str(~"init", |s| objc::sel_registerName(s));

    let mut obj = objc::objc_msgSend(MyObject, alloc);
    obj = objc::objc_msgSend(obj, init);
    objc::objc_msgSend(obj, doSomething);
}

<commit_msg>Fix botched fmt<commit_after>use std;

type id = libc::intptr_t;
type Class = libc::intptr_t;
type IMP = *u8;
type SEL = libc::intptr_t;
type Ivar = libc::intptr_t;

const nil : id = 0 as id;

extern mod objc {
    fn class_addMethod(cls : Class,
                       name : SEL,
                       imp : IMP,
                       types : *libc::c_char) -> bool;
    fn class_addIvar(cls : Class,
                     name : *libc::c_char,
                     size : libc::size_t,
                     alignment: u8,
		     types: *libc::c_char) -> bool;
    fn object_setInstanceVariable(obj : id,
                                  name : *libc::c_char,
                                  value : *libc::c_void);
    fn object_getInstanceVariable(obj : id,
                                  name : *libc::c_char,
                                  outValue : **libc::c_void);
    fn objc_allocateClassPair(superclass : Class,
                              name : *libc::c_char,
                              extraBytes : libc::size_t) -> Class;
    fn objc_getClass(name : *libc::c_char) -> id;
    fn objc_msgSend(theReceiver : id, theSelector : SEL) -> id;
    fn objc_registerClassPair(cls : Class);
    fn sel_registerName(name : *libc::c_char) -> SEL;
}

#[test]
fn test_nsapp() {
    let klass = str::as_c_str(~"NSApplication", |s|
        objc::objc_getClass(s)
    );

    let sel = str::as_c_str(~"sharedApplication", |s|
        objc::sel_registerName(s)
    );

    let nsapp = objc::objc_msgSend(klass, sel);

    io::println(#fmt("nsapp: %d", (nsapp as int)));
}

#[test]
fn test_custom_obj() {
    extern fn MyObject_doSomething(this : id, _sel : SEL) -> id {
        io::println("doSomething");
        ret this;
    }

    let NSObject = str::as_c_str(~"NSObject", |s|
        objc::objc_getClass(s)
    );
    let MyObject = str::as_c_str(~"MyObject", |s|
        objc::objc_allocateClassPair(NSObject, s, 0 as libc::size_t)
    );
    let doSomething = str::as_c_str(~"doSomething", |s|
        objc::sel_registerName(s)
    );
    let _ = str::as_c_str(~"@@:", |types|
        objc::class_addMethod(MyObject, doSomething, MyObject_doSomething,
                              types)
    );
    objc::objc_registerClassPair(MyObject);

    let alloc = str::as_c_str(~"alloc", |s| objc::sel_registerName(s));
    let init = str::as_c_str(~"init", |s| objc::sel_registerName(s));

    let mut obj = objc::objc_msgSend(MyObject, alloc);
    obj = objc::objc_msgSend(obj, init);
    objc::objc_msgSend(obj, doSomething);
}

<|endoftext|>


<commit_before>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// 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 libc::{c_int, c_char};

pub fn chown(r_path: *const c_char, uid: u32, gid: u32) -> c_int {
    unimplemented!();
}

pub fn chmod(r_path: *const c_char, mode: u32) -> c_int {
    unimplemented!();
}
<commit_msg>Just enough code to make the core crate tests pass<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// 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 libc::{c_int, c_char};
use std::ffi::CStr;
use std::path::Path;

pub fn chown(r_path: *const c_char, uid: u32, gid: u32) -> c_int {
    unimplemented!();
}

pub fn chmod(r_path: *const c_char, mode: u32) -> c_int {
    unsafe {
        let path = CStr::from_ptr(r_path).to_str().unwrap();
        match Path::new(path).exists() {
            false => 1,
            true => 0
        }
    }
}
<|endoftext|>


<commit_before>use crate::Msg;
use seed::prelude::*;

pub mod perfects_utils {
    use num_bigint::{BigUint, ToBigUint};
    use num_traits::ToPrimitive;

    #[derive(Clone)]
    pub struct Perfect {
        pub n: u64,
        pub p: u64,
        pub digits: u64,
        pub discovery: String,
    }

    #[derive(Clone)]
    pub struct PerfectDownload {
        pub n: u64,
        pub p: u64,
    }

    pub fn perfects() -> Vec<Perfect> {
        vec![
            Perfect {
                n: 51,
                p: 82589934,
                digits: 49724095,
                discovery: String::from("2018 Laroche, Woltman, Kurowski, Blosser, et al."),
            },
            Perfect {
                n: 50,
                p: 77232917,
                digits: 46498850,
                discovery: String::from(
                    "2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al..",
                ),
            },
            Perfect {
                n: 49,
                p: 74207281,
                digits: 44677235,
                discovery: String::from("2016 Cooper, Woltman, Kurowski, Blosser et al."),
            },
            Perfect {
                n: 48,
                p: 57885161,
                digits: 34850340,
                discovery: String::from("2013 Cooper, Woltman, Kurowski, et al."),
            },
            Perfect {
                n: 47,
                p: 43112609,
                digits: 25956377,
                discovery: String::from("2008 Smith, Woltman, Kurowski, et al."),
            },
            Perfect {
                n: 46,
                p: 42643801,
                digits: 42643801,
                discovery: String::from("2009 Strindmo, Woltman, Kurowski, et al."),
            },
            Perfect {
                n: 45,
                p: 37156667,
                digits: 22370543,
                discovery: String::from("2008 Elvenich, Woltman, Kurowski, et al."),
            },
            Perfect {
                n: 44,
                p: 32582657,
                digits: 19616714,
                discovery: String::from("2006 Cooper, Boone, Woltman, Kurowski, et al."),
            },
            Perfect {
                n: 43,
                p: 30402457,
                digits: 18304103,
                discovery: String::from("2005 Cooper, Boone, Woltman, Kurowski, et al."),
            },
            Perfect {
                n: 42,
                p: 25964951,
                digits: 15632458,
                discovery: String::from("2005 Nowak, Woltman, Kurowski, et. al."),
            },
            Perfect {
                n: 41,
                p: 24036583,
                digits: 14471465,
                discovery: String::from("2004 Findley, Woltman, Kurowski, et. al."),
            },
            Perfect {
                n: 40,
                p: 20996011,
                digits: 12640858,
                discovery: String::from("2003 Shafer, Woltman, Kurowski, et. al."),
            },
            Perfect {
                n: 39,
                p: 13466917,
                digits: 8107892,
                discovery: String::from("2001 Cameron, Woltman, Kurowski, et. al."),
            },
            Perfect {
                n: 38,
                p: 6972593,
                digits: 4197919,
                discovery: String::from("1999 Hajratwala, Woltman, Kurowski, et. al."),
            },
            Perfect {
                n: 37,
                p: 3021377,
                digits: 1819050,
                discovery: String::from("1998 Clarkson, Woltman, Kurowski, et. al."),
            },
            Perfect {
                n: 36,
                p: 2976221,
                digits: 1791864,
                discovery: String::from("1997 Spence, Woltman, et. al."),
            },
            Perfect {
                n: 35,
                p: 1398269,
                digits: 841842,
                discovery: String::from("1996 Armengaud, Woltman, et. al."),
            },
            Perfect {
                n: 34,
                p: 1257787,
                digits: 757263,
                discovery: String::from("1996 Slowinski & Gage"),
            },
            Perfect {
                n: 33,
                p: 859433,
                digits: 517430,
                discovery: String::from("1994 Slowinski & Gage"),
            },
            Perfect {
                n: 32,
                p: 756839,
                digits: 455663,
                discovery: String::from("1992 Slowinski & Gage"),
            },
            Perfect {
                n: 31,
                p: 216091,
                digits: 130100,
                discovery: String::from("1985 Slowinski"),
            },
            Perfect {
                n: 30,
                p: 132049,
                digits: 79502,
                discovery: String::from("1983 Slowinski"),
            },
            Perfect {
                n: 29,
                p: 110503,
                digits: 66530,
                discovery: String::from("1988 Colquitt & Welsh"),
            },
            Perfect {
                n: 28,
                p: 86243,
                digits: 51924,
                discovery: String::from("1982 Slowinski"),
            },
            Perfect {
                n: 27,
                p: 44497,
                digits: 26790,
                discovery: String::from("1979 Nelson & Slowinski"),
            },
            Perfect {
                n: 26,
                p: 23209,
                digits: 13973,
                discovery: String::from("1979 Noll"),
            },
            Perfect {
                n: 25,
                p: 21701,
                digits: 13066,
                discovery: String::from("1978 Noll & Nickel"),
            },
            Perfect {
                n: 24,
                p: 19937,
                digits: 12003,
                discovery: String::from("1971 Tuckerman"),
            },
            Perfect {
                n: 23,
                p: 11213,
                digits: 6751,
                discovery: String::from("1963 Gillies"),
            },
            Perfect {
                n: 22,
                p: 9941,
                digits: 5985,
                discovery: String::from("1963 Gillies"),
            },
            Perfect {
                n: 21,
                p: 9689,
                digits: 5834,
                discovery: String::from("1963 Gillies"),
            },
            Perfect {
                n: 20,
                p: 4423,
                digits: 2663,
                discovery: String::from("1961 Hurwitz"),
            },
            Perfect {
                n: 19,
                p: 4253,
                digits: 2561,
                discovery: String::from("1961 Hurwitz"),
            },
            Perfect {
                n: 18,
                p: 3217,
                digits: 1937,
                discovery: String::from("1957 Riesel"),
            },
            Perfect {
                n: 17,
                p: 2281,
                digits: 1373,
                discovery: String::from("1952 Robinson"),
            },
            Perfect {
                n: 16,
                p: 2203,
                digits: 1327,
                discovery: String::from("1952 Robinson"),
            },
            Perfect {
                n: 15,
                p: 1279,
                digits: 770,
                discovery: String::from("1952 Robinson"),
            },
            Perfect {
                n: 14,
                p: 607,
                digits: 366,
                discovery: String::from("1952 Robinson"),
            },
            Perfect {
                n: 13,
                p: 521,
                digits: 314,
                discovery: String::from("1952 Robinson"),
            },
            Perfect {
                n: 12,
                p: 127,
                digits: 77,
                discovery: String::from("1876 Lucas"),
            },
            Perfect {
                n: 11,
                p: 107,
                digits: 65,
                discovery: String::from("1914 Powers"),
            },
            Perfect {
                n: 10,
                p: 89,
                digits: 54,
                discovery: String::from("1911 Powers"),
            },
            Perfect {
                n: 9,
                p: 61,
                digits: 37,
                discovery: String::from("1883 Pervushin"),
            },
            Perfect {
                n: 8,
                p: 31,
                digits: 19,
                discovery: String::from("1772 Euler"),
            },
            Perfect {
                n: 7,
                p: 19,
                digits: 12,
                discovery: String::from("1588 Cataldi"),
            },
            Perfect {
                n: 6,
                p: 17,
                digits: 10,
                discovery: String::from("1588 Cataldi"),
            },
            Perfect {
                n: 5,
                p: 13,
                digits: 8,
                discovery: String::from("1456 ?"),
            },
            Perfect {
                n: 4,
                p: 7,
                digits: 4,
                discovery: String::from("?"),
            },
            Perfect {
                n: 3,
                p: 5,
                digits: 3,
                discovery: String::from("?"),
            },
            Perfect {
                n: 2,
                p: 3,
                digits: 2,
                discovery: String::from("?"),
            },
            Perfect {
                n: 1,
                p: 2,
                digits: 1,
                discovery: String::from("?"),
            },
        ]
    }

    pub fn equation(p: u64) -> BigUint {
        let two: BigUint = 2.to_biguint().unwrap();
        let power: BigUint = two.clone() << (p.to_usize().unwrap() - 1 - 1);
        power.clone() * ((power.clone() * two.clone()) - 1.to_biguint().unwrap())
    }
}

pub fn render(model: &crate::Model) -> Node<Msg> {
    let mut html = vec![];
    let perfects = perfects_utils::perfects().to_owned();

    for perfect in perfects.iter() {
        let perfectp: u64 = perfect.p;
        let perfect_download = perfects_utils::PerfectDownload {
            n: perfect.n,
            p: perfect.p,
        };
        let equation: String = format!(
            "2{} × (2{}-1)",
            &(perfectp - 1).to_string(),
            &(perfectp).to_string()
        );

        html.push(tr![
            td![perfect.n.to_string()],      //rank
            td![El::from_html(&equation)],   //perfect number as a formula
            td![perfect.digits.to_string()], //digits in length
            td![perfect.discovery],          //discovery
            if model.download.n == perfect.n {
                td![crate::utils::generate_file(
                    model.download.n,
                    perfects_utils::equation(model.download.p)
                )]
            } else {
                td![button![
                    "Generate",
                    mouse_ev("mouseup", move |event| Msg::GeneratePerfectDownload(
                        event,
                        perfect_download
                    ))
                ]]
            },
        ]);
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs! {At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![b!["No."]],
                    td![b!["Prime"]],
                    td![b!["Digits"]],
                    td![b!["Discovered"]],
                    td![b!["Download"]]
                ],
                html
            ]
        ]
    ]
}

#[cfg(test)]
use num_bigint::BigUint;
#[cfg(test)]
use num_traits::Num;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn perfect_test<'a>() {
        let mut perfects: Vec<perfects_utils::Perfect> = perfects_utils::perfects();
        perfects.reverse();
        assert_eq!(perfects[50].digits, 49724095);
        assert_eq!(perfects[49].digits, 46498850);
        assert_eq!(perfects[39].digits, 12640858);
    }

    #[test]
    fn equation_test() {
        let mut number: BigUint;

        number = num_bigint::BigUint::from_str_radix("6", 10).unwrap();
        assert_eq!(perfects_utils::equation(2), number);

        number = num_bigint::BigUint::from_str_radix("137438691328", 10).unwrap();
        assert_eq!(perfects_utils::equation(19), number);

        number = num_bigint::BigUint::from_str_radix("2658455991569831744654692615953842176", 10)
            .unwrap();
        assert_eq!(perfects_utils::equation(61), number);
    }
}
<commit_msg>Fixed compile error<commit_after>use crate::Msg;
use seed::prelude::*;

pub mod perfects_utils {
    use num_bigint::{BigUint, ToBigUint};
    use num_traits::ToPrimitive;

    #[derive(Clone)]
    pub struct Perfect {
        pub n: u64,
        pub p: u64,
        pub digits: u64,
        pub discovery: String,
    }

    #[derive(Clone)]
    pub struct PerfectDownload {
        pub n: u64,
        pub p: u64,
    }

    pub fn perfects() -> Vec<Perfect> {
        vec![
            Perfect {
                n: 51,
                p: 82589934,
                digits: 49724095,
                discovery: String::from("2018 Laroche, Woltman, Kurowski, Blosser, et al."),
            },
            Perfect {
                n: 50,
                p: 77232917,
                digits: 46498850,
                discovery: String::from(
                    "2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al..",
                ),
            },
            Perfect {
                n: 49,
                p: 74207281,
                digits: 44677235,
                discovery: String::from("2016 Cooper, Woltman, Kurowski, Blosser et al."),
            },
            Perfect {
                n: 48,
                p: 57885161,
                digits: 34850340,
                discovery: String::from("2013 Cooper, Woltman, Kurowski, et al."),
            },
            Perfect {
                n: 47,
                p: 43112609,
                digits: 25956377,
                discovery: String::from("2008 Smith, Woltman, Kurowski, et al."),
            },
            Perfect {
                n: 46,
                p: 42643801,
                digits: 42643801,
                discovery: String::from("2009 Strindmo, Woltman, Kurowski, et al."),
            },
            Perfect {
                n: 45,
                p: 37156667,
                digits: 22370543,
                discovery: String::from("2008 Elvenich, Woltman, Kurowski, et al."),
            },
            Perfect {
                n: 44,
                p: 32582657,
                digits: 19616714,
                discovery: String::from("2006 Cooper, Boone, Woltman, Kurowski, et al."),
            },
            Perfect {
                n: 43,
                p: 30402457,
                digits: 18304103,
                discovery: String::from("2005 Cooper, Boone, Woltman, Kurowski, et al."),
            },
            Perfect {
                n: 42,
                p: 25964951,
                digits: 15632458,
                discovery: String::from("2005 Nowak, Woltman, Kurowski, et. al."),
            },
            Perfect {
                n: 41,
                p: 24036583,
                digits: 14471465,
                discovery: String::from("2004 Findley, Woltman, Kurowski, et. al."),
            },
            Perfect {
                n: 40,
                p: 20996011,
                digits: 12640858,
                discovery: String::from("2003 Shafer, Woltman, Kurowski, et. al."),
            },
            Perfect {
                n: 39,
                p: 13466917,
                digits: 8107892,
                discovery: String::from("2001 Cameron, Woltman, Kurowski, et. al."),
            },
            Perfect {
                n: 38,
                p: 6972593,
                digits: 4197919,
                discovery: String::from("1999 Hajratwala, Woltman, Kurowski, et. al."),
            },
            Perfect {
                n: 37,
                p: 3021377,
                digits: 1819050,
                discovery: String::from("1998 Clarkson, Woltman, Kurowski, et. al."),
            },
            Perfect {
                n: 36,
                p: 2976221,
                digits: 1791864,
                discovery: String::from("1997 Spence, Woltman, et. al."),
            },
            Perfect {
                n: 35,
                p: 1398269,
                digits: 841842,
                discovery: String::from("1996 Armengaud, Woltman, et. al."),
            },
            Perfect {
                n: 34,
                p: 1257787,
                digits: 757263,
                discovery: String::from("1996 Slowinski & Gage"),
            },
            Perfect {
                n: 33,
                p: 859433,
                digits: 517430,
                discovery: String::from("1994 Slowinski & Gage"),
            },
            Perfect {
                n: 32,
                p: 756839,
                digits: 455663,
                discovery: String::from("1992 Slowinski & Gage"),
            },
            Perfect {
                n: 31,
                p: 216091,
                digits: 130100,
                discovery: String::from("1985 Slowinski"),
            },
            Perfect {
                n: 30,
                p: 132049,
                digits: 79502,
                discovery: String::from("1983 Slowinski"),
            },
            Perfect {
                n: 29,
                p: 110503,
                digits: 66530,
                discovery: String::from("1988 Colquitt & Welsh"),
            },
            Perfect {
                n: 28,
                p: 86243,
                digits: 51924,
                discovery: String::from("1982 Slowinski"),
            },
            Perfect {
                n: 27,
                p: 44497,
                digits: 26790,
                discovery: String::from("1979 Nelson & Slowinski"),
            },
            Perfect {
                n: 26,
                p: 23209,
                digits: 13973,
                discovery: String::from("1979 Noll"),
            },
            Perfect {
                n: 25,
                p: 21701,
                digits: 13066,
                discovery: String::from("1978 Noll & Nickel"),
            },
            Perfect {
                n: 24,
                p: 19937,
                digits: 12003,
                discovery: String::from("1971 Tuckerman"),
            },
            Perfect {
                n: 23,
                p: 11213,
                digits: 6751,
                discovery: String::from("1963 Gillies"),
            },
            Perfect {
                n: 22,
                p: 9941,
                digits: 5985,
                discovery: String::from("1963 Gillies"),
            },
            Perfect {
                n: 21,
                p: 9689,
                digits: 5834,
                discovery: String::from("1963 Gillies"),
            },
            Perfect {
                n: 20,
                p: 4423,
                digits: 2663,
                discovery: String::from("1961 Hurwitz"),
            },
            Perfect {
                n: 19,
                p: 4253,
                digits: 2561,
                discovery: String::from("1961 Hurwitz"),
            },
            Perfect {
                n: 18,
                p: 3217,
                digits: 1937,
                discovery: String::from("1957 Riesel"),
            },
            Perfect {
                n: 17,
                p: 2281,
                digits: 1373,
                discovery: String::from("1952 Robinson"),
            },
            Perfect {
                n: 16,
                p: 2203,
                digits: 1327,
                discovery: String::from("1952 Robinson"),
            },
            Perfect {
                n: 15,
                p: 1279,
                digits: 770,
                discovery: String::from("1952 Robinson"),
            },
            Perfect {
                n: 14,
                p: 607,
                digits: 366,
                discovery: String::from("1952 Robinson"),
            },
            Perfect {
                n: 13,
                p: 521,
                digits: 314,
                discovery: String::from("1952 Robinson"),
            },
            Perfect {
                n: 12,
                p: 127,
                digits: 77,
                discovery: String::from("1876 Lucas"),
            },
            Perfect {
                n: 11,
                p: 107,
                digits: 65,
                discovery: String::from("1914 Powers"),
            },
            Perfect {
                n: 10,
                p: 89,
                digits: 54,
                discovery: String::from("1911 Powers"),
            },
            Perfect {
                n: 9,
                p: 61,
                digits: 37,
                discovery: String::from("1883 Pervushin"),
            },
            Perfect {
                n: 8,
                p: 31,
                digits: 19,
                discovery: String::from("1772 Euler"),
            },
            Perfect {
                n: 7,
                p: 19,
                digits: 12,
                discovery: String::from("1588 Cataldi"),
            },
            Perfect {
                n: 6,
                p: 17,
                digits: 10,
                discovery: String::from("1588 Cataldi"),
            },
            Perfect {
                n: 5,
                p: 13,
                digits: 8,
                discovery: String::from("1456 ?"),
            },
            Perfect {
                n: 4,
                p: 7,
                digits: 4,
                discovery: String::from("?"),
            },
            Perfect {
                n: 3,
                p: 5,
                digits: 3,
                discovery: String::from("?"),
            },
            Perfect {
                n: 2,
                p: 3,
                digits: 2,
                discovery: String::from("?"),
            },
            Perfect {
                n: 1,
                p: 2,
                digits: 1,
                discovery: String::from("?"),
            },
        ]
    }

    pub fn equation(p: u64) -> BigUint {
        let two: BigUint = 2.to_biguint().unwrap();
        let power: BigUint = two.clone() << (p.to_usize().unwrap() - 1 - 1);
        power.clone() * ((power.clone() * two.clone()) - 1.to_biguint().unwrap())
    }
}

pub fn render(model: &crate::Model) -> Node<Msg> {
    let mut html = vec![];
    let perfects = perfects_utils::perfects().to_owned();

    for perfect in perfects.iter() {
        let perfectp: u64 = perfect.p;
        let perfect_download = perfects_utils::PerfectDownload {
            n: perfect.n,
            p: perfect.p,
        };
        let equation: String = format!(
            "2{} × (2{}-1)",
            &(perfectp - 1).to_string(),
            &(perfectp).to_string()
        );

        html.push(tr![
            td![perfect.n.to_string()],      //rank
            td![El::from_html(&equation)],   //perfect number as a formula
            td![perfect.digits.to_string()], //digits in length
            td![perfect.discovery.to_string()],          //discovery
            if model.download.n == perfect.n {
                td![crate::utils::generate_file(
                    model.download.n,
                    perfects_utils::equation(model.download.p)
                )]
            } else {
                td![button![
                    "Generate",
                    mouse_ev("mouseup", move |event| Msg::GeneratePerfectDownload(
                        event,
                        perfect_download
                    ))
                ]]
            },
        ]);
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs! {At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![b!["No."]],
                    td![b!["Prime"]],
                    td![b!["Digits"]],
                    td![b!["Discovered"]],
                    td![b!["Download"]]
                ],
                html
            ]
        ]
    ]
}

#[cfg(test)]
use num_bigint::BigUint;
#[cfg(test)]
use num_traits::Num;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn perfect_test<'a>() {
        let mut perfects: Vec<perfects_utils::Perfect> = perfects_utils::perfects();
        perfects.reverse();
        assert_eq!(perfects[50].digits, 49724095);
        assert_eq!(perfects[49].digits, 46498850);
        assert_eq!(perfects[39].digits, 12640858);
    }

    #[test]
    fn equation_test() {
        let mut number: BigUint;

        number = num_bigint::BigUint::from_str_radix("6", 10).unwrap();
        assert_eq!(perfects_utils::equation(2), number);

        number = num_bigint::BigUint::from_str_radix("137438691328", 10).unwrap();
        assert_eq!(perfects_utils::equation(19), number);

        number = num_bigint::BigUint::from_str_radix("2658455991569831744654692615953842176", 10)
            .unwrap();
        assert_eq!(perfects_utils::equation(61), number);
    }
}
<|endoftext|>


<commit_before>use beacon_node::ProductionBeaconNode;
use clap::{App, Arg, ArgMatches};
use env_logger::{Builder, Env};
use environment::EnvironmentBuilder;
use eth2_testnet_config::{Eth2TestnetConfig, DEFAULT_HARDCODED_TESTNET};
use lighthouse_version::VERSION;
use slog::{crit, info, warn};
use std::path::PathBuf;
use std::process::exit;
use types::EthSpec;
use validator_client::ProductionValidatorClient;

pub const DEFAULT_DATA_DIR: &str = ".lighthouse";
pub const ETH2_CONFIG_FILENAME: &str = "eth2-spec.toml";

fn bls_library_name() -> &'static str {
    if cfg!(feature = "portable") {
        "blst-portable"
    } else if cfg!(feature = "milagro") {
        "milagro"
    } else {
        "blst"
    }
}

fn main() {
    // Parse the CLI parameters.
    let matches = App::new("Lighthouse")
        .version(VERSION)
        .author("Sigma Prime <contact@sigmaprime.io>")
        .setting(clap::AppSettings::ColoredHelp)
        .about(
            "Ethereum 2.0 client by Sigma Prime. Provides a full-featured beacon \
             node, a validator client and utilities for managing validator accounts.",
        )
        .long_version(
            format!(
                "{}\n\
                 BLS Library: {}",
                 VERSION, bls_library_name()
            ).as_str()
        )
        .arg(
            Arg::with_name("spec")
                .short("s")
                .long("spec")
                .value_name("TITLE")
                .help("Specifies the default eth2 spec type.")
                .takes_value(true)
                .possible_values(&["mainnet", "minimal", "interop"])
                .global(true)
                .default_value("mainnet"),
        )
        .arg(
            Arg::with_name("env_log")
                .short("l")
                .help("Enables environment logging giving access to sub-protocol logs such as discv5 and libp2p",
                )
                .takes_value(false),
        )
        .arg(
            Arg::with_name("logfile")
                .long("logfile")
                .value_name("FILE")
                .help(
                    "File path where output will be written. Default file logging format is JSON.",
                )
                .takes_value(true),
        )
        .arg(
            Arg::with_name("log-format")
                .long("log-format")
                .value_name("FORMAT")
                .help("Specifies the format used for logging.")
                .possible_values(&["JSON"])
                .takes_value(true),
        )
        .arg(
            Arg::with_name("debug-level")
                .long("debug-level")
                .value_name("LEVEL")
                .help("The verbosity level for emitting logs.")
                .takes_value(true)
                .possible_values(&["info", "debug", "trace", "warn", "error", "crit"])
                .global(true)
                .default_value("info"),
        )
        .arg(
            Arg::with_name("datadir")
                .long("datadir")
                .short("d")
                .value_name("DIR")
                .global(true)
                .help("Data directory for lighthouse keys and databases.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("testnet-dir")
                .short("t")
                .long("testnet-dir")
                .value_name("DIR")
                .help(
                    "Path to directory containing eth2_testnet specs. Defaults to \
                      a hard-coded Lighthouse testnet. Only effective if there is no \
                      existing database.",
                )
                .takes_value(true)
                .global(true),
        )
        .arg(
            Arg::with_name("testnet")
                .long("testnet")
                .value_name("testnet")
                .help("Name of network lighthouse will connect to")
                .possible_values(&["medalla", "altona"])
                .conflicts_with("testnet-dir")
                .takes_value(true)
                .global(true)

        )
        .subcommand(beacon_node::cli_app())
        .subcommand(boot_node::cli_app())
        .subcommand(validator_client::cli_app())
        .subcommand(account_manager::cli_app())
        .get_matches();

    // boot node subcommand circumvents the environment
    if let Some(bootnode_matches) = matches.subcommand_matches("boot_node") {
        // The bootnode uses the main debug-level flag
        let debug_info = matches
            .value_of("debug-level")
            .expect("Debug-level must be present")
            .into();
        boot_node::run(bootnode_matches, debug_info);
        return;
    }

    // Debugging output for libp2p and external crates.
    if matches.is_present("env_log") {
        Builder::from_env(Env::default()).init();
    }

    macro_rules! run_with_spec {
        ($env_builder: expr) => {
            run($env_builder, &matches)
        };
    }

    let result = match matches.value_of("spec") {
        Some("minimal") => run_with_spec!(EnvironmentBuilder::minimal()),
        Some("mainnet") => run_with_spec!(EnvironmentBuilder::mainnet()),
        Some("interop") => run_with_spec!(EnvironmentBuilder::interop()),
        spec => {
            // This path should be unreachable due to slog having a `default_value`
            unreachable!("Unknown spec configuration: {:?}", spec);
        }
    };

    // `std::process::exit` does not run destructors so we drop manually.
    drop(matches);

    // Return the appropriate error code.
    match result {
        Ok(()) => exit(0),
        Err(e) => {
            eprintln!("{}", e);
            drop(e);
            exit(1)
        }
    }
}

fn run<E: EthSpec>(
    environment_builder: EnvironmentBuilder<E>,
    matches: &ArgMatches,
) -> Result<(), String> {
    if std::mem::size_of::<usize>() != 8 {
        return Err(format!(
            "{}bit architecture is not supported (64bit only).",
            std::mem::size_of::<usize>() * 8
        ));
    }

    let debug_level = matches
        .value_of("debug-level")
        .ok_or_else(|| "Expected --debug-level flag".to_string())?;

    let log_format = matches.value_of("log-format");

    // Parse testnet config from the `testnet` and `testnet-dir` flag in that order
    // else, use the default
    let mut optional_testnet_config = Eth2TestnetConfig::hard_coded_default()?;
    if matches.is_present("testnet") {
        optional_testnet_config = clap_utils::parse_hardcoded_network(matches, "testnet")?;
    };
    if matches.is_present("testnet-dir") {
        optional_testnet_config = clap_utils::parse_testnet_dir(matches, "testnet-dir")?;
    };

    let mut environment = environment_builder
        .async_logger(debug_level, log_format)?
        .multi_threaded_tokio_runtime()?
        .optional_eth2_testnet_config(optional_testnet_config)?
        .build()?;

    let log = environment.core_context().log().clone();

    if let Some(log_path) = matches.value_of("logfile") {
        let path = log_path
            .parse::<PathBuf>()
            .map_err(|e| format!("Failed to parse log path: {:?}", e))?;
        environment.log_to_json_file(path, debug_level, log_format)?;
    }

    // Note: the current code technically allows for starting a beacon node _and_ a validator
    // client at the same time.
    //
    // Whilst this is possible, the mutual-exclusivity of `clap` sub-commands prevents it from
    // actually happening.
    //
    // Creating a command which can run both might be useful future works.

    // Print an indication of which network is currently in use.
    let optional_testnet = clap_utils::parse_optional::<String>(matches, "testnet")?;
    let optional_testnet_dir = clap_utils::parse_optional::<PathBuf>(matches, "testnet-dir")?;

    let testnet_name = match (optional_testnet, optional_testnet_dir) {
        (Some(testnet), None) => testnet,
        (None, Some(testnet_dir)) => format!("custom ({})", testnet_dir.display()),
        (None, None) => DEFAULT_HARDCODED_TESTNET.to_string(),
        (Some(_), Some(_)) => panic!("CLI prevents both --testnet and --testnet-dir"),
    };

    if let Some(sub_matches) = matches.subcommand_matches("account_manager") {
        eprintln!("Running account manager for {} testnet", testnet_name);
        // Pass the entire `environment` to the account manager so it can run blocking operations.
        account_manager::run(sub_matches, environment)?;

        // Exit as soon as account manager returns control.
        return Ok(());
    };

    warn!(
        log,
        "Ethereum 2.0 is pre-release. This software is experimental."
    );
    info!(
        log,
        "Configured for testnet";
        "name" => testnet_name
    );

    let beacon_node = if let Some(sub_matches) = matches.subcommand_matches("beacon_node") {
        let runtime_context = environment.core_context();

        let beacon = environment
            .runtime()
            .block_on(ProductionBeaconNode::new_from_cli(
                runtime_context,
                sub_matches,
            ))
            .map_err(|e| format!("Failed to start beacon node: {}", e))?;

        Some(beacon)
    } else {
        None
    };

    let validator_client = if let Some(sub_matches) = matches.subcommand_matches("validator_client")
    {
        let runtime_context = environment.core_context();

        let mut validator = environment
            .runtime()
            .block_on(ProductionValidatorClient::new_from_cli(
                runtime_context,
                sub_matches,
            ))
            .map_err(|e| format!("Failed to init validator client: {}", e))?;

        environment
            .core_context()
            .executor
            .runtime_handle()
            .enter(|| {
                validator
                    .start_service()
                    .map_err(|e| format!("Failed to start validator client service: {}", e))
            })?;

        Some(validator)
    } else {
        None
    };

    if beacon_node.is_none() && validator_client.is_none() {
        crit!(log, "No subcommand supplied. See --help .");
        return Err("No subcommand supplied.".into());
    }

    // Block this thread until Crtl+C is pressed.
    environment.block_until_ctrl_c()?;
    info!(log, "Shutting down..");

    environment.fire_signal();
    drop(beacon_node);
    drop(validator_client);

    // Shutdown the environment once all tasks have completed.
    environment.shutdown_on_idle();
    Ok(())
}
<commit_msg>Fix double lighthouse (#1473)<commit_after>use beacon_node::ProductionBeaconNode;
use clap::{App, Arg, ArgMatches};
use env_logger::{Builder, Env};
use environment::EnvironmentBuilder;
use eth2_testnet_config::{Eth2TestnetConfig, DEFAULT_HARDCODED_TESTNET};
use lighthouse_version::VERSION;
use slog::{crit, info, warn};
use std::path::PathBuf;
use std::process::exit;
use types::EthSpec;
use validator_client::ProductionValidatorClient;

pub const DEFAULT_DATA_DIR: &str = ".lighthouse";
pub const ETH2_CONFIG_FILENAME: &str = "eth2-spec.toml";

fn bls_library_name() -> &'static str {
    if cfg!(feature = "portable") {
        "blst-portable"
    } else if cfg!(feature = "milagro") {
        "milagro"
    } else {
        "blst"
    }
}

fn main() {
    // Parse the CLI parameters.
    let matches = App::new("Lighthouse")
        .version(VERSION.replace("Lighthouse/", "").as_str())
        .author("Sigma Prime <contact@sigmaprime.io>")
        .setting(clap::AppSettings::ColoredHelp)
        .about(
            "Ethereum 2.0 client by Sigma Prime. Provides a full-featured beacon \
             node, a validator client and utilities for managing validator accounts.",
        )
        .long_version(
            format!(
                "{}\n\
                 BLS Library: {}",
                 VERSION.replace("Lighthouse/", ""), bls_library_name()
            ).as_str()
        )
        .arg(
            Arg::with_name("spec")
                .short("s")
                .long("spec")
                .value_name("TITLE")
                .help("Specifies the default eth2 spec type.")
                .takes_value(true)
                .possible_values(&["mainnet", "minimal", "interop"])
                .global(true)
                .default_value("mainnet"),
        )
        .arg(
            Arg::with_name("env_log")
                .short("l")
                .help("Enables environment logging giving access to sub-protocol logs such as discv5 and libp2p",
                )
                .takes_value(false),
        )
        .arg(
            Arg::with_name("logfile")
                .long("logfile")
                .value_name("FILE")
                .help(
                    "File path where output will be written. Default file logging format is JSON.",
                )
                .takes_value(true),
        )
        .arg(
            Arg::with_name("log-format")
                .long("log-format")
                .value_name("FORMAT")
                .help("Specifies the format used for logging.")
                .possible_values(&["JSON"])
                .takes_value(true),
        )
        .arg(
            Arg::with_name("debug-level")
                .long("debug-level")
                .value_name("LEVEL")
                .help("The verbosity level for emitting logs.")
                .takes_value(true)
                .possible_values(&["info", "debug", "trace", "warn", "error", "crit"])
                .global(true)
                .default_value("info"),
        )
        .arg(
            Arg::with_name("datadir")
                .long("datadir")
                .short("d")
                .value_name("DIR")
                .global(true)
                .help("Data directory for lighthouse keys and databases.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("testnet-dir")
                .short("t")
                .long("testnet-dir")
                .value_name("DIR")
                .help(
                    "Path to directory containing eth2_testnet specs. Defaults to \
                      a hard-coded Lighthouse testnet. Only effective if there is no \
                      existing database.",
                )
                .takes_value(true)
                .global(true),
        )
        .arg(
            Arg::with_name("testnet")
                .long("testnet")
                .value_name("testnet")
                .help("Name of network lighthouse will connect to")
                .possible_values(&["medalla", "altona"])
                .conflicts_with("testnet-dir")
                .takes_value(true)
                .global(true)

        )
        .subcommand(beacon_node::cli_app())
        .subcommand(boot_node::cli_app())
        .subcommand(validator_client::cli_app())
        .subcommand(account_manager::cli_app())
        .get_matches();

    // boot node subcommand circumvents the environment
    if let Some(bootnode_matches) = matches.subcommand_matches("boot_node") {
        // The bootnode uses the main debug-level flag
        let debug_info = matches
            .value_of("debug-level")
            .expect("Debug-level must be present")
            .into();
        boot_node::run(bootnode_matches, debug_info);
        return;
    }

    // Debugging output for libp2p and external crates.
    if matches.is_present("env_log") {
        Builder::from_env(Env::default()).init();
    }

    macro_rules! run_with_spec {
        ($env_builder: expr) => {
            run($env_builder, &matches)
        };
    }

    let result = match matches.value_of("spec") {
        Some("minimal") => run_with_spec!(EnvironmentBuilder::minimal()),
        Some("mainnet") => run_with_spec!(EnvironmentBuilder::mainnet()),
        Some("interop") => run_with_spec!(EnvironmentBuilder::interop()),
        spec => {
            // This path should be unreachable due to slog having a `default_value`
            unreachable!("Unknown spec configuration: {:?}", spec);
        }
    };

    // `std::process::exit` does not run destructors so we drop manually.
    drop(matches);

    // Return the appropriate error code.
    match result {
        Ok(()) => exit(0),
        Err(e) => {
            eprintln!("{}", e);
            drop(e);
            exit(1)
        }
    }
}

fn run<E: EthSpec>(
    environment_builder: EnvironmentBuilder<E>,
    matches: &ArgMatches,
) -> Result<(), String> {
    if std::mem::size_of::<usize>() != 8 {
        return Err(format!(
            "{}bit architecture is not supported (64bit only).",
            std::mem::size_of::<usize>() * 8
        ));
    }

    let debug_level = matches
        .value_of("debug-level")
        .ok_or_else(|| "Expected --debug-level flag".to_string())?;

    let log_format = matches.value_of("log-format");

    // Parse testnet config from the `testnet` and `testnet-dir` flag in that order
    // else, use the default
    let mut optional_testnet_config = Eth2TestnetConfig::hard_coded_default()?;
    if matches.is_present("testnet") {
        optional_testnet_config = clap_utils::parse_hardcoded_network(matches, "testnet")?;
    };
    if matches.is_present("testnet-dir") {
        optional_testnet_config = clap_utils::parse_testnet_dir(matches, "testnet-dir")?;
    };

    let mut environment = environment_builder
        .async_logger(debug_level, log_format)?
        .multi_threaded_tokio_runtime()?
        .optional_eth2_testnet_config(optional_testnet_config)?
        .build()?;

    let log = environment.core_context().log().clone();

    if let Some(log_path) = matches.value_of("logfile") {
        let path = log_path
            .parse::<PathBuf>()
            .map_err(|e| format!("Failed to parse log path: {:?}", e))?;
        environment.log_to_json_file(path, debug_level, log_format)?;
    }

    // Note: the current code technically allows for starting a beacon node _and_ a validator
    // client at the same time.
    //
    // Whilst this is possible, the mutual-exclusivity of `clap` sub-commands prevents it from
    // actually happening.
    //
    // Creating a command which can run both might be useful future works.

    // Print an indication of which network is currently in use.
    let optional_testnet = clap_utils::parse_optional::<String>(matches, "testnet")?;
    let optional_testnet_dir = clap_utils::parse_optional::<PathBuf>(matches, "testnet-dir")?;

    let testnet_name = match (optional_testnet, optional_testnet_dir) {
        (Some(testnet), None) => testnet,
        (None, Some(testnet_dir)) => format!("custom ({})", testnet_dir.display()),
        (None, None) => DEFAULT_HARDCODED_TESTNET.to_string(),
        (Some(_), Some(_)) => panic!("CLI prevents both --testnet and --testnet-dir"),
    };

    if let Some(sub_matches) = matches.subcommand_matches("account_manager") {
        eprintln!("Running account manager for {} testnet", testnet_name);
        // Pass the entire `environment` to the account manager so it can run blocking operations.
        account_manager::run(sub_matches, environment)?;

        // Exit as soon as account manager returns control.
        return Ok(());
    };

    warn!(
        log,
        "Ethereum 2.0 is pre-release. This software is experimental."
    );
    info!(
        log,
        "Configured for testnet";
        "name" => testnet_name
    );

    let beacon_node = if let Some(sub_matches) = matches.subcommand_matches("beacon_node") {
        let runtime_context = environment.core_context();

        let beacon = environment
            .runtime()
            .block_on(ProductionBeaconNode::new_from_cli(
                runtime_context,
                sub_matches,
            ))
            .map_err(|e| format!("Failed to start beacon node: {}", e))?;

        Some(beacon)
    } else {
        None
    };

    let validator_client = if let Some(sub_matches) = matches.subcommand_matches("validator_client")
    {
        let runtime_context = environment.core_context();

        let mut validator = environment
            .runtime()
            .block_on(ProductionValidatorClient::new_from_cli(
                runtime_context,
                sub_matches,
            ))
            .map_err(|e| format!("Failed to init validator client: {}", e))?;

        environment
            .core_context()
            .executor
            .runtime_handle()
            .enter(|| {
                validator
                    .start_service()
                    .map_err(|e| format!("Failed to start validator client service: {}", e))
            })?;

        Some(validator)
    } else {
        None
    };

    if beacon_node.is_none() && validator_client.is_none() {
        crit!(log, "No subcommand supplied. See --help .");
        return Err("No subcommand supplied.".into());
    }

    // Block this thread until Crtl+C is pressed.
    environment.block_until_ctrl_c()?;
    info!(log, "Shutting down..");

    environment.fire_signal();
    drop(beacon_node);
    drop(validator_client);

    // Shutdown the environment once all tasks have completed.
    environment.shutdown_on_idle();
    Ok(())
}
<|endoftext|>


<commit_before>use iced::{
  canvas, executor, mouse, Application, Canvas, Color, Command, Element, Length, Point, Rectangle, Settings, Vector,
};
use oppai_field::field::{self, Field, Pos};
use oppai_field::player::Player;
use oppai_field::zobrist::Zobrist;
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;

const FIELD_WIDTH: u32 = 39;
const FIELD_HEIGHT: u32 = 32;

pub fn main() {
  Game::run(Settings {
    antialiasing: true,
    ..Settings::default()
  });
}

struct Game {
  player: Player,
  field: Field,
  captures: Vec<(Vec<Pos>, Player)>,
}

#[derive(Debug, Clone, Copy)]
enum Message {
  PutPoint(Pos),
}

impl Application for Game {
  type Executor = executor::Null;
  type Message = Message;
  type Flags = ();

  fn new(_flags: ()) -> (Self, Command<Self::Message>) {
    let mut rng = XorShiftRng::from_entropy();
    let zobrist = Zobrist::new(field::length(FIELD_WIDTH, FIELD_HEIGHT) * 2, &mut rng);
    let field = Field::new(FIELD_WIDTH, FIELD_HEIGHT, std::sync::Arc::new(zobrist));
    (
      Game {
        player: Player::Red,
        field,
        captures: Vec::new(),
      },
      Command::none(),
    )
  }

  fn title(&self) -> String {
    "OpPAI".into()
  }

  fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
    let Message::PutPoint(pos) = message;
    if self.field.put_point(pos, self.player) {
      let last_chain = self.field.get_last_chain();
      if let Some(&pos) = last_chain.first() {
        let player = self.field.cell(pos).get_player();
        self.captures.push((last_chain, player));
      }

      let n = self.field.n(pos);
      let s = self.field.s(pos);
      let w = self.field.w(pos);
      let e = self.field.e(pos);
      let nw = self.field.nw(pos);
      let ne = self.field.ne(pos);
      let sw = self.field.sw(pos);
      let se = self.field.se(pos);

      let mut check = |pos1: Pos, pos2: Pos| {
        if self.field.cell(pos1).get_players_point() == Some(self.player)
          && self.field.cell(pos2).get_players_point() == Some(self.player)
        {
          self.captures.push((vec![pos, pos1, pos2], self.player));
          true
        } else {
          false
        }
      };

      let _ = !check(s, e) && (check(s, se) || check(e, se));
      let _ = !check(e, n) && (check(e, ne) || check(n, ne));
      let _ = !check(n, w) && (check(n, nw) || check(w, nw));
      let _ = !check(w, s) && (check(w, sw) || check(s, sw));

      self.player = self.player.next();
    }

    Command::none()
  }

  fn view(&mut self) -> iced::Element<'_, Self::Message> {
    let canvas = Canvas::new(self).height(Length::Fill).width(Length::Fill);
    Element::<Pos>::from(canvas).map(Message::PutPoint)
  }
}

impl canvas::Program<Pos> for Game {
  fn update(&mut self, event: canvas::Event, bounds: Rectangle, cursor: canvas::Cursor) -> Option<Pos> {
    let cursor_position = cursor.position_in(&bounds)?;
    let canvas::Event::Mouse(mouse_event) = event;
    match mouse_event {
      mouse::Event::ButtonPressed(mouse::Button::Left) => {
        let field_width = self.field.width();
        let field_height = self.field.height();
        let width = bounds
          .width
          .min(bounds.height / field_height as f32 * field_width as f32);
        let height = bounds
          .height
          .min(bounds.width / field_width as f32 * field_height as f32);
        let step_x = width / field_width as f32;
        let step_y = height / field_height as f32;
        let shift = Vector::new(
          ((bounds.width - width) / 2.0).round() + step_x / 2.0,
          ((bounds.height - height) / 2.0).round() + step_y / 2.0,
        );

        let point = cursor_position - shift;
        if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
          let x = (point.x / step_x).round() as u32;
          let y = (point.y / step_y).round() as u32;
          Some(self.field.to_pos(x, y))
        } else {
          None
        }
      }
      _ => None,
    }
  }

  fn draw(&self, bounds: Rectangle, cursor: canvas::Cursor) -> Vec<canvas::Geometry> {
    let mut frame = canvas::Frame::new(bounds.size());

    let field_width = self.field.width();
    let field_height = self.field.height();
    let width = frame
      .width()
      .min(frame.height() / field_height as f32 * field_width as f32);
    let height = frame
      .height()
      .min(frame.width() / field_width as f32 * field_height as f32);
    let step_x = width / field_width as f32;
    let step_y = height / field_height as f32;
    let shift = Vector::new(
      ((frame.width() - width) / 2.0).round(),
      ((frame.height() - height) / 2.0).round(),
    );

    let grid = canvas::Path::new(|path| {
      for x in 0..field_width {
        let offset = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
        path.move_to(Point::new(offset, 0.0) + shift);
        path.line_to(Point::new(offset, height) + shift);
      }
      for y in 0..field_height {
        let offset = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
        path.move_to(Point::new(0.0, offset) + shift);
        path.line_to(Point::new(width, offset) + shift);
      }
    });

    frame.stroke(
      &grid,
      canvas::Stroke {
        width: 1.0,
        color: Color::BLACK,
        ..canvas::Stroke::default()
      },
    );

    fn color(player: Player) -> Color {
      match player {
        Player::Red => Color::from_rgb8(0xFF, 0x00, 0x00),
        Player::Black => Color::BLACK,
      }
    }

    let xy_to_point = |x: u32, y: u32| {
      let offset_x = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
      let offset_y = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
      Point::new(offset_x, offset_y) + shift
    };
    let pos_to_point = |pos: Pos| {
      let x = self.field.to_x(pos);
      let y = self.field.to_y(pos);
      xy_to_point(x, y)
    };

    for &player in &[Player::Red, Player::Black] {
      let points = canvas::Path::new(|path| {
        for &pos in self
          .field
          .points_seq()
          .iter()
          .filter(|&&pos| self.field.cell(pos).is_players_point(player))
        {
          path.circle(pos_to_point(pos), 5.0)
        }
      });

      frame.fill(&points, color(player));
    }

    for (chain, player) in &self.captures {
      let path = canvas::Path::new(|path| {
        path.move_to(pos_to_point(chain[0]));
        for &pos in chain.iter().skip(1) {
          path.line_to(pos_to_point(pos));
        }
      });

      let mut color = color(*player);
      color.a = 0.5;

      frame.fill(&path, color);
    }

    if let Some(&pos) = self.field.points_seq().last() {
      let last_point = canvas::Path::new(|path| path.circle(pos_to_point(pos), 8.0));

      let color = color(self.field.cell(pos).get_player());

      frame.stroke(
        &last_point,
        canvas::Stroke {
          width: 2.0,
          color,
          ..canvas::Stroke::default()
        },
      );
    }

    if let Some(point) = cursor.position().and_then(|c| {
      let point = c - shift - Vector::new(step_x / 2.0, step_y / 2.0);
      if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
        let x = (point.x / step_x).round() as u32;
        let y = (point.y / step_y).round() as u32;
        let pos = self.field.to_pos(x, y);
        if self.field.is_putting_allowed(pos) {
          Some(xy_to_point(x, y))
        } else {
          None
        }
      } else {
        None
      }
    }) {
      let cursor_point = canvas::Path::new(|path| path.circle(point, 5.0));

      let mut color = color(self.player);
      color.a = 0.5;

      frame.fill(&cursor_point, color);
    }

    vec![frame.into_geometry()]
  }
}
<commit_msg>Fix boundaries check.<commit_after>use iced::{
  canvas, executor, mouse, Application, Canvas, Color, Command, Element, Length, Point, Rectangle, Settings, Vector,
};
use oppai_field::field::{self, Field, Pos};
use oppai_field::player::Player;
use oppai_field::zobrist::Zobrist;
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;

const FIELD_WIDTH: u32 = 39;
const FIELD_HEIGHT: u32 = 32;

pub fn main() {
  Game::run(Settings {
    antialiasing: true,
    ..Settings::default()
  });
}

struct Game {
  player: Player,
  field: Field,
  captures: Vec<(Vec<Pos>, Player)>,
}

#[derive(Debug, Clone, Copy)]
enum Message {
  PutPoint(Pos),
}

impl Application for Game {
  type Executor = executor::Null;
  type Message = Message;
  type Flags = ();

  fn new(_flags: ()) -> (Self, Command<Self::Message>) {
    let mut rng = XorShiftRng::from_entropy();
    let zobrist = Zobrist::new(field::length(FIELD_WIDTH, FIELD_HEIGHT) * 2, &mut rng);
    let field = Field::new(FIELD_WIDTH, FIELD_HEIGHT, std::sync::Arc::new(zobrist));
    (
      Game {
        player: Player::Red,
        field,
        captures: Vec::new(),
      },
      Command::none(),
    )
  }

  fn title(&self) -> String {
    "OpPAI".into()
  }

  fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
    let Message::PutPoint(pos) = message;
    if self.field.put_point(pos, self.player) {
      let last_chain = self.field.get_last_chain();
      if let Some(&pos) = last_chain.first() {
        let player = self.field.cell(pos).get_player();
        self.captures.push((last_chain, player));
      }

      let n = self.field.n(pos);
      let s = self.field.s(pos);
      let w = self.field.w(pos);
      let e = self.field.e(pos);
      let nw = self.field.nw(pos);
      let ne = self.field.ne(pos);
      let sw = self.field.sw(pos);
      let se = self.field.se(pos);

      let mut check = |pos1: Pos, pos2: Pos| {
        if self.field.cell(pos1).get_players_point() == Some(self.player)
          && self.field.cell(pos2).get_players_point() == Some(self.player)
        {
          self.captures.push((vec![pos, pos1, pos2], self.player));
          true
        } else {
          false
        }
      };

      let _ = !check(s, e) && (check(s, se) || check(e, se));
      let _ = !check(e, n) && (check(e, ne) || check(n, ne));
      let _ = !check(n, w) && (check(n, nw) || check(w, nw));
      let _ = !check(w, s) && (check(w, sw) || check(s, sw));

      self.player = self.player.next();
    }

    Command::none()
  }

  fn view(&mut self) -> iced::Element<'_, Self::Message> {
    let canvas = Canvas::new(self).height(Length::Fill).width(Length::Fill);
    Element::<Pos>::from(canvas).map(Message::PutPoint)
  }
}

impl canvas::Program<Pos> for Game {
  fn update(&mut self, event: canvas::Event, bounds: Rectangle, cursor: canvas::Cursor) -> Option<Pos> {
    let cursor_position = cursor.position_in(&bounds)?;
    let canvas::Event::Mouse(mouse_event) = event;
    match mouse_event {
      mouse::Event::ButtonPressed(mouse::Button::Left) => {
        let field_width = self.field.width();
        let field_height = self.field.height();
        let width = bounds
          .width
          .min(bounds.height / field_height as f32 * field_width as f32);
        let height = bounds
          .height
          .min(bounds.width / field_width as f32 * field_height as f32);
        let step_x = width / field_width as f32;
        let step_y = height / field_height as f32;
        let shift = Vector::new(
          ((bounds.width - width) / 2.0).round(),
          ((bounds.height - height) / 2.0).round(),
        );
        let cursor_shift = Vector::new(step_x / 2.0, step_y / 2.0);

        let point = cursor_position - shift;
        if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
          let point = point - cursor_shift;
          let x = (point.x / step_x).round() as u32;
          let y = (point.y / step_y).round() as u32;
          Some(self.field.to_pos(x, y))
        } else {
          None
        }
      }
      _ => None,
    }
  }

  fn draw(&self, bounds: Rectangle, cursor: canvas::Cursor) -> Vec<canvas::Geometry> {
    let mut frame = canvas::Frame::new(bounds.size());

    let field_width = self.field.width();
    let field_height = self.field.height();
    let width = frame
      .width()
      .min(frame.height() / field_height as f32 * field_width as f32);
    let height = frame
      .height()
      .min(frame.width() / field_width as f32 * field_height as f32);
    let step_x = width / field_width as f32;
    let step_y = height / field_height as f32;
    let shift = Vector::new(
      ((frame.width() - width) / 2.0).round(),
      ((frame.height() - height) / 2.0).round(),
    );
    let cursor_shift = Vector::new(step_x / 2.0, step_y / 2.0);

    let grid = canvas::Path::new(|path| {
      for x in 0..field_width {
        let offset = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
        path.move_to(Point::new(offset, 0.0) + shift);
        path.line_to(Point::new(offset, height) + shift);
      }
      for y in 0..field_height {
        let offset = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
        path.move_to(Point::new(0.0, offset) + shift);
        path.line_to(Point::new(width, offset) + shift);
      }
    });

    frame.stroke(
      &grid,
      canvas::Stroke {
        width: 1.0,
        color: Color::BLACK,
        ..canvas::Stroke::default()
      },
    );

    fn color(player: Player) -> Color {
      match player {
        Player::Red => Color::from_rgb8(0xFF, 0x00, 0x00),
        Player::Black => Color::BLACK,
      }
    }

    let xy_to_point = |x: u32, y: u32| {
      let offset_x = (step_x * x as f32 + step_x / 2.0).round() + 0.5;
      let offset_y = (step_y * y as f32 + step_y / 2.0).round() + 0.5;
      Point::new(offset_x, offset_y) + shift
    };
    let pos_to_point = |pos: Pos| {
      let x = self.field.to_x(pos);
      let y = self.field.to_y(pos);
      xy_to_point(x, y)
    };

    for &player in &[Player::Red, Player::Black] {
      let points = canvas::Path::new(|path| {
        for &pos in self
          .field
          .points_seq()
          .iter()
          .filter(|&&pos| self.field.cell(pos).is_players_point(player))
        {
          path.circle(pos_to_point(pos), 5.0)
        }
      });

      frame.fill(&points, color(player));
    }

    for (chain, player) in &self.captures {
      let path = canvas::Path::new(|path| {
        path.move_to(pos_to_point(chain[0]));
        for &pos in chain.iter().skip(1) {
          path.line_to(pos_to_point(pos));
        }
      });

      let mut color = color(*player);
      color.a = 0.5;

      frame.fill(&path, color);
    }

    if let Some(&pos) = self.field.points_seq().last() {
      let last_point = canvas::Path::new(|path| path.circle(pos_to_point(pos), 8.0));

      let color = color(self.field.cell(pos).get_player());

      frame.stroke(
        &last_point,
        canvas::Stroke {
          width: 2.0,
          color,
          ..canvas::Stroke::default()
        },
      );
    }

    if let Some(point) = cursor.position().and_then(|cursor_position| {
      let point = cursor_position - shift;
      if point.x >= 0.0 && point.x <= width && point.y >= 0.0 && point.y <= height {
        let point = point - cursor_shift;
        let x = (point.x / step_x).round() as u32;
        let y = (point.y / step_y).round() as u32;
        let pos = self.field.to_pos(x, y);
        if self.field.is_putting_allowed(pos) {
          Some(xy_to_point(x, y))
        } else {
          None
        }
      } else {
        None
      }
    }) {
      let cursor_point = canvas::Path::new(|path| path.circle(point, 5.0));

      let mut color = color(self.player);
      color.a = 0.5;

      frame.fill(&cursor_point, color);
    }

    vec![frame.into_geometry()]
  }
}
<|endoftext|>