"crypto-common",
]
+[[package]]
+name = "dotenv"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
+
[[package]]
name = "encoding_rs"
version = "0.8.32"
name = "podium"
version = "0.1.0"
dependencies = [
+ "dotenv",
"podman-api",
"poise",
"serde_path_to_error",
poise = "0.5.5"
serde_path_to_error = "0.1.13"
tokio = { version = "1.29.1", features = ["macros", "rt-multi-thread"]}
+dotenv = "0.15.0"
\ No newline at end of file
--- /dev/null
+use std::collections::HashMap;
+use std::ops::Deref;
+use std::process;
+use std::sync::{Arc, Mutex};
+use std::time::{Instant, Duration};
+use podman_api::models::{Container, MountPoint, Port, PortMapping};
+use podman_api::opts::ContainerListOpts;
+use podman_api::Podman;
+use crate::utils::Id;
+
+pub(crate) struct Containers {
+ cache: Arc<Mutex<Option<(Instant, HashMap<[u8; 32], Container>)>>>,
+ connection: Podman,
+}
+
+impl Containers {
+ pub(crate) fn connect(uri: &str) -> Containers {
+ let connection = match Podman::new(uri) {
+ Ok(a) => a,
+ Err(e) => {
+ eprintln!("An error has occurred: {}", e);
+ process::exit(32);
+ }
+ };
+ let c = Containers {
+ cache: Arc::new(Mutex::new(None)),
+ connection,
+ };
+ c
+ }
+
+ fn time_since_update(&self) -> Duration {
+ let i = match self.cache.lock().unwrap().deref() {
+ Some(i) => { i.0 }
+ None => { return Duration::MAX; }
+ };
+ Instant::now().duration_since(i)
+ }
+
+ pub(crate) async fn sync(&self) -> Result<(), ContainerError> {
+ if self.time_since_update() > Duration::new(60, 0) {
+ return match self.sync_helper().await {
+ Ok(_) => { Ok(()) }
+ Err(e) => { Err(e) }
+ };
+ }
+ Ok(())
+ }
+
+ async fn sync_helper(&self) -> Result<(), ContainerError> {
+ let containers_options = ContainerListOpts::builder().all(true).sync(true).build();
+
+ let list_containers_response = match self.connection.containers().list(&containers_options).await {
+ Ok(r) => { r }
+ Err(e) => { return Err(ContainerError::PodmanError(e)); }
+ };
+
+ let mut containers: HashMap<[u8; 32], Container> = HashMap::new();
+
+ for c in list_containers_response {
+ let id = Id::hex_id_to_byte_array(match &c.id {
+ Some(id) => { id }
+ None => { return Err(ContainerError::UnableToParseId); }
+ });
+
+ let container: Container = Container {
+ adjust_cpu_shares: None,
+ command: Some(match c.command {
+ None => { String::from("Unknown") }
+ Some(command) => { command[0].clone() }
+ }),
+ config: None,
+ created: match c.created {
+ Some(created) => {
+ Some(created.timestamp())
+ }
+ None => { None }
+ },
+ host_config: None,
+ id: c.id,
+ image: c.image,
+ image_id: c.image_id,
+ labels: c.labels,
+ mounts: None,
+ name: match &c.names {
+ None => { None }
+ Some(n) => { Some(n[0].clone()) }
+ },
+ names: c.names,
+ network_settings: None,
+ networking_config: None,
+ platform: None,
+ ports: match c.ports {
+ None => { None }
+ Some(p) => {
+ let mut ports: Vec<Port> = Vec::new();
+ for port_mapping in p {
+ let port = Port {
+ ip: port_mapping.host_ip,
+ private_port: match port_mapping.container_port {
+ None => { continue; }
+ Some(p) => { p }
+ },
+ public_port: match port_mapping.host_port {
+ None => { None }
+ Some(p) => { Some(p) }
+ },
+ type_: "".to_string(),
+ };
+ ports.push(port);
+ }
+ Some(ports)
+ }
+ },
+ size_root_fs: None,
+ size_rw: None,
+ state: c.state,
+ status: c.status,
+ };
+
+ containers.insert(id, container);
+ }
+
+ Ok(())
+ }
+}
+
+#[derive(Debug)]
+pub(crate) enum ContainerError {
+ UnableToParseId,
+ PodmanError(podman_api::Error),
+}
\ No newline at end of file
mod utils;
+mod containers;
use crate::utils::*;
use podman_api::opts::ContainerListOpts;
use podman_api::Podman;
use poise::serenity_prelude as serenity;
use std::process;
+use dotenv::dotenv;
use tokio;
+use crate::containers::{ContainerError, Containers};
/// Display's the connected podman's version information
#[poise::command(slash_command, prefix_command)]
Ok(())
}
+async fn list_containers(ctx: Context<'_>) -> Result<(), Error> {
+ let info_response = match ctx.data().podman.info().await {
+ Ok(v) => v,
+ Err(e) => {
+ eprintln!("unable too get podman version.");
+ create_embed!(&ctx, "Error", format!("```{}```", e));
+ return Ok(());
+ }
+ };
+
+ let containers_options = ContainerListOpts::builder().all(true).sync(true).build();
+ let containers_response = match ctx
+ .data()
+ .podman
+ .containers()
+ .list(&containers_options)
+ .await
+ {
+ Ok(containers_response) => containers_response,
+ Err(e) => {
+ eprintln!("unable too get podman containers.");
+ create_embed!(&ctx, "Error", format!("```{}```", e));
+ return Ok(());
+ }
+ };
+
+ let mut container_list: Vec<(String, String)> = Vec::new();
+ container_list.reserve(containers_response.len());
+
+
+ todo!()
+}
+
#[tokio::main]
async fn main() {
- let podman = match Podman::new("unix:///run/podman/podman.sock") {
+ let api_uri = "unix:///run/podman/podman.sock";
+ let podman = match Podman::new(&api_uri) {
Ok(a) => a,
Err(e) => {
eprintln!("An error has occurred: {}", e);
process::exit(32);
}
};
+
+ let containers = Containers::connect(&api_uri);
+
+ match containers.sync().await {
+ Ok(_) => {}
+ Err(e) => {
+ eprintln!("{:#?}", e);
+ process::exit(31)
+ }
+ }
+
+ dotenv().ok();
let framework = poise::Framework::builder()
.options(poise::FrameworkOptions {
commands: vec![version(), system_info()],
.parse()
.unwrap(),
podman,
+ containers,
})
})
});
+use std::num::ParseIntError;
use podman_api::Podman;
+use crate::containers::Containers;
pub(crate) struct EmbedData;
pub(crate) struct Data {
pub(crate) podman: Podman,
pub(crate) podman_version: String,
+ pub(crate) containers: Containers,
}
+pub(crate) struct Id;
+
+impl Id {
+ pub(crate) fn hex_id_to_byte_array(id: &String) -> [u8; 32] {
+ let id_working_len: usize;
+ if id.len() / 2 > 32 {
+ id_working_len = 64;
+ } else {
+ id_working_len = (id.len() / 2) * 2;
+ }
+
+ let id_bytes_vec: Result<Vec<u8>, ParseIntError> = (0..id_working_len)
+ .step_by(2)
+ .map(|i| u8::from_str_radix(&id[i..i + 2], 16))
+ .collect();
+
+ match id_bytes_vec {
+ Ok(b) => {
+ let mut a: [u8; 32] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+ for i in 0..b[..id_working_len / 2].len() {
+ a[i] = b[i];
+ }
+ a
+ }
+ Err(_) => {
+ return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+ }
+ }
+ }
+}
+
+
// User data, which is stored and accessible in all command invocations
pub(crate) type Error = Box<dyn std::error::Error + Send + Sync>;
pub(crate) type Context<'a> = poise::Context<'a, Data, Error>;
+
#[macro_export]
macro_rules! create_embed {
($ctx:expr, $title:expr, $($field_title:expr => $field_data:expr),*) => {