use byte_unit::{Byte, ByteUnit};
use chrono::{DateTime, NaiveDateTime, Utc};
use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
use colored::Colorize;
use discord::Client;
use discord_sdk::activity::{ActivityArgs, ActivityKind, Assets, IntoTimestamp, Timestamps};
use std::{
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
time::{Duration, SystemTime},
};
use sysinfo::{System, SystemExt};
use tokio::{task::block_in_place, time::Interval};
mod discord;
struct Ts(u64);
impl IntoTimestamp for Ts {
fn into_timestamp(self) -> i64 {
self.0 as i64
}
}
async fn update_discord(client: &Client, system: &mut System) {
system.refresh_cpu();
system.refresh_memory();
let processors = system.processors().len();
let total_memory = Byte::from_unit(system.total_memory() as f64, ByteUnit::KB).unwrap();
let total_memory = total_memory.get_adjusted_unit(ByteUnit::GB);
let used_memory = Byte::from_unit(system.used_memory() as f64, ByteUnit::KB).unwrap();
let used_memory = used_memory.get_adjusted_unit(ByteUnit::GB);
let used_percent = used_memory.get_value() / total_memory.get_value();
let load = system.load_average();
let boot_time = system.boot_time();
let os_name = system.name();
let os_version = system.os_version();
let kernel_version = system.kernel_version();
let rp = discord_sdk::activity::ActivityBuilder::default()
.state(format!(
"CORES: {} | MEM: {}",
processors,
total_memory.to_string()
))
.details(format!("CPU: {:.2}% | RAM: {:.2}%", load.one, used_percent));
let image_string;
if cfg!(windows) {
image_string = "os-windows";
} else if cfg!(linux) {
image_string = "os-linux";
} else {
image_string =match os_type::current_platform().os_type {
os_type::OSType::OSX => "os_unix",
os_type::OSType::Unknown => "os_unix",
_ => "os-linux",
};
}
let mut activity: ActivityArgs = rp.into();
let inner = activity.activity.as_mut().unwrap();
inner.assets = Some(Assets {
large_image: Some(image_string.to_string()),
large_text: Some(format!(
"{} {}",
os_name.unwrap_or("Unknown".to_string()),
os_version.unwrap_or("".to_string())
)),
small_image: Some("dot-blue".to_string()),
small_text: kernel_version,
});
client.discord.update_activity(activity).await.unwrap();
}
async fn rpc_runner_run(running: &Arc<AtomicBool>, interval: &mut Interval, client: &Client) {
let mut system = System::default();
while running.load(Ordering::SeqCst) {
interval.tick().await;
update_discord(client, &mut system).await;
}
}
#[tokio::main]
async fn main() {
let matches = App::new(crate_name!())
.author(crate_authors!())
.about(crate_description!())
.version(crate_version!())
.arg(
Arg::with_name("interval")
.long("interval")
.short("i")
.default_value("1")
.help("Number of seconds to wait between updates")
.required(false)
.takes_value(true),
)
.get_matches();
let interval_int: u64 = matches
.value_of("interval")
.unwrap()
.parse()
.expect("Interval must be an integer");
let mut interval = tokio::time::interval(Duration::from_secs(interval_int));
let discord_client = discord::make_client(discord_sdk::Subscriptions::ACTIVITY).await;
let mut activity_events = discord_client.wheel.activity();
let running = Arc::new(AtomicBool::new(true));
{
let r = running.clone();
ctrlc::set_handler(move || {
r.store(false, Ordering::SeqCst);
})
.expect("Error setting Ctrl-C handler");
}
tokio::task::spawn(async move {
while let Ok(ae) = activity_events.0.recv().await {
tracing::info!(event = ?ae, "received activity event");
}
});
println!("{}", "Press CTRL+C to stop".blue());
rpc_runner_run(&running, &mut interval, &discord_client).await;
println!("{}", "Shutting down".blue());
discord_client.discord.disconnect().await;
}