1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use crate::connection::Connection;
use crate::protocol::{Protocol, NetworkProtocol};
use crate::metric::{MetricData, Namespace};
use std::net::IpAddr;
use crate::MetricalError;

/// Options used to determine when to send metrics from memory to a server.
#[derive(Clone)]
pub struct FlushConfigurationOptions {
    pub flush_after_amount: Option<usize>,
    pub flush_after_interval: Option<u64>

}

/// Nonessential options available to a configuration
pub struct ConfigurationOptions {
    pub namespace: Option<Namespace>,
    pub flush: FlushConfigurationOptions
}

/// A configuration of the metrical library.
///
/// This configuration contains information necessary to send messages to Graphite
/// and information on which protocol to use to communicate with Graphite/Statsd
pub struct Configuration {
    connection: Connection,
    pub protocol: Protocol,
    pub options: ConfigurationOptions,
}

/// Helper to build a configuration piece by piece.
pub struct ConfigurationBuilder {
    ip_addr: Option<IpAddr>,
    port: Option<u16>,
    network_protocol: Option<NetworkProtocol>,
    namespace: Option<Namespace>,
    protocol: Option<Protocol>,
    flush_after_amount: Option<usize>,
    flush_after_interval: Option<u64>
}

impl Default for ConfigurationBuilder {
    fn default() -> Self {
        ConfigurationBuilder {
            ip_addr: None,
            port: None,
            network_protocol: None,
            protocol: None,
            namespace: None,
            flush_after_amount: None,
            flush_after_interval: None
        }
    }
}

impl ConfigurationBuilder {
    pub fn new() -> Self {
        ConfigurationBuilder::default()
    }

    pub fn ip_addr(mut self, ip_addr: IpAddr) -> Self {
        self.ip_addr = Some(ip_addr);
        self
    }

    pub fn port(mut self, port: u16) -> Self {
        self.port = Some(port);
        self
    }

    pub fn flush_after_amount(mut self, amount: Option<usize>) -> Self {
        self.flush_after_amount = amount;
        self
    }

    pub fn flush_after_interval(mut self, interval: Option<u64>) -> Self {
        self.flush_after_interval = interval;
        self
    }

    pub fn protocol(mut self, protocol: Protocol) -> Self {
        self.protocol = Some(protocol);
        self
    }

    pub fn network_protocol(mut self, protocol: NetworkProtocol) -> Self {
        self.network_protocol = Some(protocol);
        self
    }

    pub fn namespace(mut self, namespace: Option<Namespace>) -> Self {
        self.namespace = namespace;
        self
    }

    pub fn build(self) -> Result<Configuration, MetricalError>  {
        let protocol = if self.protocol.is_none() {
            return Err(MetricalError::ConfigurationInvalid("Protocol Unspecified"));
        } else {
            self.protocol.unwrap()
        };

        let network_protocol = if self.network_protocol.is_none() {
            return Err(MetricalError::ConfigurationInvalid("Network Protocol unspecified"))
        } else { self.network_protocol.unwrap() };

        let ip_addr = if self.ip_addr.is_some() { self.ip_addr.unwrap() } else {
            return Err(MetricalError::ConfigurationInvalid("IP Address unspecified"))
        };

        let port = if self.port.is_some() { self.port.unwrap() } else {
            return Err(MetricalError::ConfigurationInvalid("Port unspecified"))
        };

        let configuration_options = ConfigurationOptions{
            namespace: self.namespace,
            flush: FlushConfigurationOptions {
                flush_after_interval: self.flush_after_interval,
                flush_after_amount: self.flush_after_amount
            }
        };

        let connection = Connection::new(ip_addr, port, network_protocol);
        Ok(Configuration::new(connection, protocol, configuration_options))
    }
}

impl Configuration {
    pub fn new(connection: Connection, protocol: Protocol, options: ConfigurationOptions)
        -> Configuration
    {
        Configuration{
            connection,
            protocol,
            options,
        }
    }
}

impl Configuration {
    pub fn send(&mut self,  data: Vec<MetricData>) {
        let data = self.protocol.serialize(data);

        for packet_body in data {
            match self.connection.send(packet_body.as_ref()) {
                Ok(_) => {},
                Err(_) => {}
            };
        }
    }
}