pub mod host;
use std::collections::HashMap;
use std::net::IpAddr;
use std::time::SystemTime;
use chrono::DateTime;
use local_ip_address::list_afinet_netifas;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::host::HostInfo;
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
pub struct Heartbeat {
pub hb_type: HeartbeatType,
pub timestamp: DateTime<chrono::Utc>,
pub hb_uuid: Uuid,
pub payload: Vec<HeartbeatPayload>,
}
impl Heartbeat {
pub fn new(
hb_type: HeartbeatType,
name: String,
agent_status: Option<AgentStatus>,
) -> Heartbeat {
let status = match agent_status {
Some(s) => s,
None => AgentStatus::Undefined,
};
Heartbeat {
hb_type,
timestamp: DateTime::from(SystemTime::now()),
hb_uuid: Uuid::new_v4(),
payload: vec![
HeartbeatPayload::AgentInfo(AgentInfo { status, name }),
HeartbeatPayload::HostInfo(HostInfo::new()),
HeartbeatPayload::BuildInfo(BuildInfo::new()),
HeartbeatPayload::NetInterfaceInfo(
NetInterfaceInfo::from_network_interfaces()
.expect("Could not generate network interface info"),
),
],
}
}
pub fn compact(payload: Vec<HeartbeatPayloadType>) -> Heartbeat {
let mut hb = Heartbeat {
hb_type: HeartbeatType::Compact,
timestamp: DateTime::from(SystemTime::now()),
hb_uuid: Uuid::new_v4(),
payload: vec![],
};
for p in payload.iter() {
hb.payload.push(p.to_payload())
}
hb
}
}
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
pub enum HeartbeatPayloadType {
AgentInfo(AgentStatus, String),
HostInfo,
BuildInfo,
NetInterfaceInfo,
}
impl HeartbeatPayloadType {
pub fn to_payload(&self) -> HeartbeatPayload {
match self {
HeartbeatPayloadType::AgentInfo(status, name) => {
HeartbeatPayload::AgentInfo(AgentInfo {
status: status.to_owned(),
name: name.to_string(),
})
}
HeartbeatPayloadType::HostInfo => HeartbeatPayload::HostInfo(HostInfo::new()),
HeartbeatPayloadType::BuildInfo => HeartbeatPayload::BuildInfo(BuildInfo::new()),
HeartbeatPayloadType::NetInterfaceInfo => HeartbeatPayload::NetInterfaceInfo(
NetInterfaceInfo::from_network_interfaces()
.expect("Could not generate network interface info"),
),
}
}
}
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
pub enum HeartbeatPayload {
AgentInfo(AgentInfo),
HostInfo(HostInfo),
BuildInfo(BuildInfo),
NetInterfaceInfo(NetInterfaceInfo),
}
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
pub enum HeartbeatType {
Full,
Compact,
}
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
pub struct AgentInfo {
pub status: AgentStatus,
pub name: String,
}
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
pub enum AgentStatus {
Undefined,
Initializing,
AwaitingJoin,
Running,
Orphaned,
Exiting,
}
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
pub struct BuildInfo {
build_timestamp: String,
build_date: String,
git_branch: String,
git_timestamp: String,
git_date: String,
git_hash: String,
git_describe: String,
rustc_host_triple: String,
rustc_version: String,
cargo_target_triple: String,
}
impl BuildInfo {
fn new() -> BuildInfo {
BuildInfo {
build_timestamp: String::from(env!("VERGEN_BUILD_TIMESTAMP")),
build_date: String::from(env!("VERGEN_BUILD_DATE")),
git_branch: String::from(env!("VERGEN_GIT_BRANCH")),
git_timestamp: String::from(env!("VERGEN_GIT_COMMIT_TIMESTAMP")),
git_date: String::from(env!("VERGEN_GIT_COMMIT_DATE")),
git_hash: String::from(env!("VERGEN_GIT_SHA")),
git_describe: String::from(env!("VERGEN_GIT_DESCRIBE")),
rustc_host_triple: String::from(env!("VERGEN_RUSTC_HOST_TRIPLE")),
rustc_version: String::from(env!("VERGEN_RUSTC_SEMVER")),
cargo_target_triple: String::from(env!("VERGEN_CARGO_TARGET_TRIPLE")),
}
}
}
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
pub struct NetInterfaceInfo {
pub addresses: HashMap<String, Vec<IpAddr>>,
}
impl NetInterfaceInfo {
pub fn new() -> NetInterfaceInfo {
NetInterfaceInfo {
addresses: HashMap::new(),
}
}
pub fn from_network_interfaces() -> Result<NetInterfaceInfo, local_ip_address::Error> {
let network_interfaces = list_afinet_netifas()?;
let mut ni_info = NetInterfaceInfo::new();
for (name, ip) in network_interfaces.iter() {
if let Some(iface) = ni_info.addresses.get_mut(name) {
iface.push(*ip);
} else {
ni_info.addresses.insert(name.to_string(), vec![*ip]);
}
}
Ok(ni_info)
}
}
impl Default for NetInterfaceInfo {
fn default() -> Self {
Self::new()
}
}