feat: use ContainerId new_type
This commit is contained in:
@@ -11,6 +11,45 @@ const ONE_KB: f64 = 1000.0;
|
|||||||
const ONE_MB: f64 = ONE_KB * 1000.0;
|
const ONE_MB: f64 = ONE_KB * 1000.0;
|
||||||
const ONE_GB: f64 = ONE_MB * 1000.0;
|
const ONE_GB: f64 = ONE_MB * 1000.0;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
|
||||||
|
pub struct ContainerId(String);
|
||||||
|
|
||||||
|
impl From<String> for ContainerId {
|
||||||
|
fn from(x: String) -> Self {
|
||||||
|
Self(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&String> for ContainerId {
|
||||||
|
fn from(x: &String) -> Self {
|
||||||
|
Self(x.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for ContainerId {
|
||||||
|
fn from(x: &str) -> Self {
|
||||||
|
Self(x.to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContainerId {
|
||||||
|
pub fn get(&self) -> &str {
|
||||||
|
self.0.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for ContainerId {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.0.cmp(&other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for ContainerId {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct StatefulList<T> {
|
pub struct StatefulList<T> {
|
||||||
pub state: ListState,
|
pub state: ListState,
|
||||||
@@ -326,7 +365,7 @@ pub type CpuTuple = (Vec<(f64, f64)>, CpuStats, State);
|
|||||||
pub struct ContainerItem {
|
pub struct ContainerItem {
|
||||||
pub cpu_stats: VecDeque<CpuStats>,
|
pub cpu_stats: VecDeque<CpuStats>,
|
||||||
pub docker_controls: StatefulList<DockerControls>,
|
pub docker_controls: StatefulList<DockerControls>,
|
||||||
pub id: String,
|
pub id: ContainerId,
|
||||||
pub image: String,
|
pub image: String,
|
||||||
pub last_updated: u64,
|
pub last_updated: u64,
|
||||||
pub logs: StatefulList<ListItem<'static>>,
|
pub logs: StatefulList<ListItem<'static>>,
|
||||||
@@ -341,7 +380,7 @@ pub struct ContainerItem {
|
|||||||
|
|
||||||
impl ContainerItem {
|
impl ContainerItem {
|
||||||
/// Create a new container item
|
/// Create a new container item
|
||||||
pub fn new(id: String, status: String, image: String, state: State, name: String) -> Self {
|
pub fn new(id: ContainerId, status: String, image: String, state: State, name: String) -> Self {
|
||||||
let mut docker_controls = StatefulList::new(DockerControls::gen_vec(state));
|
let mut docker_controls = StatefulList::new(DockerControls::gen_vec(state));
|
||||||
docker_controls.start();
|
docker_controls.start();
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
+14
-19
@@ -163,20 +163,14 @@ impl AppData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Find the id of the currently selected container.
|
/// Find the id of the currently selected container.
|
||||||
/// If any containers on system, will always return a string.
|
/// If any containers on system, will always return a container id
|
||||||
/// Only returns None when no containers found.
|
/// Only returns None when no containers found.
|
||||||
pub fn get_selected_container_id(&self) -> Option<String> {
|
pub fn get_selected_container_id(&self) -> Option<ContainerId> {
|
||||||
let mut output = None;
|
let mut output = None;
|
||||||
if let Some(index) = self.containers.state.selected() {
|
if let Some(index) = self.containers.state.selected() {
|
||||||
let id = self
|
if let Some(x) = self.containers.items.get(index) {
|
||||||
.containers
|
output = Some(x.id.clone());
|
||||||
.items
|
}
|
||||||
.iter()
|
|
||||||
.skip(index)
|
|
||||||
.take(1)
|
|
||||||
.map(|i| i.id.clone())
|
|
||||||
.collect::<String>();
|
|
||||||
output = Some(id);
|
|
||||||
}
|
}
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
@@ -307,7 +301,7 @@ impl AppData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialised(&mut self, all_ids: &[(bool, String)]) -> bool {
|
pub fn initialised(&mut self, all_ids: &[(bool, ContainerId)]) -> bool {
|
||||||
let count_is_running = all_ids.iter().filter(|i| i.0).count();
|
let count_is_running = all_ids.iter().filter(|i| i.0).count();
|
||||||
let number_with_cpu_status = self
|
let number_with_cpu_status = self
|
||||||
.containers
|
.containers
|
||||||
@@ -379,7 +373,7 @@ impl AppData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get all containers ids
|
/// Get all containers ids
|
||||||
pub fn get_all_ids(&self) -> Vec<String> {
|
pub fn get_all_ids(&self) -> Vec<ContainerId> {
|
||||||
self.containers
|
self.containers
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
@@ -388,14 +382,14 @@ impl AppData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// find container given id
|
/// find container given id
|
||||||
fn get_container_by_id(&mut self, id: &str) -> Option<&mut ContainerItem> {
|
fn get_container_by_id(&mut self, id: &ContainerId) -> Option<&mut ContainerItem> {
|
||||||
self.containers.items.iter_mut().find(|i| i.id == id)
|
self.containers.items.iter_mut().find(|i| &i.id == id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update container mem, cpu, & network stats, in single function so only need to call .lock() once
|
/// Update container mem, cpu, & network stats, in single function so only need to call .lock() once
|
||||||
pub fn update_stats(
|
pub fn update_stats(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: &str,
|
id: &ContainerId,
|
||||||
cpu_stat: Option<f64>,
|
cpu_stat: Option<f64>,
|
||||||
mem_stat: Option<u64>,
|
mem_stat: Option<u64>,
|
||||||
mem_limit: u64,
|
mem_limit: u64,
|
||||||
@@ -435,7 +429,7 @@ impl AppData {
|
|||||||
if !containers
|
if !containers
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|i| i.id.as_ref())
|
.filter_map(|i| i.id.as_ref())
|
||||||
.any(|x| x == id)
|
.any(|x| ContainerId::from(x) == id.clone())
|
||||||
{
|
{
|
||||||
// If removed container is currently selected, then change selected to previous
|
// If removed container is currently selected, then change selected to previous
|
||||||
// This will default to 0 in any edge cases
|
// This will default to 0 in any edge cases
|
||||||
@@ -476,7 +470,8 @@ impl AppData {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or("".to_owned(), std::clone::Clone::clone);
|
.map_or("".to_owned(), std::clone::Clone::clone);
|
||||||
|
|
||||||
if let Some(current_container) = self.get_container_by_id(id) {
|
let id = ContainerId::from(id.as_str());
|
||||||
|
if let Some(current_container) = self.get_container_by_id(&id) {
|
||||||
if current_container.name != name {
|
if current_container.name != name {
|
||||||
current_container.name = name;
|
current_container.name = name;
|
||||||
};
|
};
|
||||||
@@ -512,7 +507,7 @@ impl AppData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// update logs of a given container, based on id
|
/// update logs of a given container, based on id
|
||||||
pub fn update_log_by_id(&mut self, output: &[String], id: &str) {
|
pub fn update_log_by_id(&mut self, output: &[String], id: &ContainerId) {
|
||||||
let tz = Self::get_systemtime();
|
let tz = Self::get_systemtime();
|
||||||
let color = self.args.color;
|
let color = self.args.color;
|
||||||
let raw = self.args.raw;
|
let raw = self.args.raw;
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
|
use crate::app_data::ContainerId;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum DockerMessage {
|
pub enum DockerMessage {
|
||||||
Update,
|
Update,
|
||||||
Start(String),
|
Start(ContainerId),
|
||||||
Restart(String),
|
Restart(ContainerId),
|
||||||
Pause(String),
|
Pause(ContainerId),
|
||||||
Unpause(String),
|
Unpause(ContainerId),
|
||||||
Stop(String),
|
Stop(ContainerId),
|
||||||
Quit,
|
Quit,
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-17
@@ -16,7 +16,7 @@ use tokio::{sync::mpsc::Receiver, task::JoinHandle};
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app_data::{AppData, DockerControls},
|
app_data::{AppData, ContainerId, DockerControls},
|
||||||
app_error::AppError,
|
app_error::AppError,
|
||||||
parse_args::CliArgs,
|
parse_args::CliArgs,
|
||||||
ui::GuiState,
|
ui::GuiState,
|
||||||
@@ -26,8 +26,8 @@ pub use message::DockerMessage;
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
|
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
|
||||||
enum SpawnId {
|
enum SpawnId {
|
||||||
Stats((String, Binate)),
|
Stats((ContainerId, Binate)),
|
||||||
Log(String),
|
Log(ContainerId),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cpu & Mem stats take twice as long as the update interval to get a value, so will have two being executed at the same time
|
/// Cpu & Mem stats take twice as long as the update interval to get a value, so will have two being executed at the same time
|
||||||
@@ -94,7 +94,7 @@ impl DockerData {
|
|||||||
/// remove if from spawns hashmap when complete
|
/// remove if from spawns hashmap when complete
|
||||||
async fn update_container_stat(
|
async fn update_container_stat(
|
||||||
docker: Arc<Docker>,
|
docker: Arc<Docker>,
|
||||||
id: String,
|
id: ContainerId,
|
||||||
app_data: Arc<Mutex<AppData>>,
|
app_data: Arc<Mutex<AppData>>,
|
||||||
is_running: bool,
|
is_running: bool,
|
||||||
spawns: Arc<Mutex<HashMap<SpawnId, JoinHandle<()>>>>,
|
spawns: Arc<Mutex<HashMap<SpawnId, JoinHandle<()>>>>,
|
||||||
@@ -102,7 +102,7 @@ impl DockerData {
|
|||||||
) {
|
) {
|
||||||
let mut stream = docker
|
let mut stream = docker
|
||||||
.stats(
|
.stats(
|
||||||
&id,
|
id.get(),
|
||||||
Some(StatsOptions {
|
Some(StatsOptions {
|
||||||
stream: false,
|
stream: false,
|
||||||
one_shot: !is_running,
|
one_shot: !is_running,
|
||||||
@@ -149,7 +149,7 @@ impl DockerData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Update all stats, spawn each container into own tokio::spawn thread
|
/// Update all stats, spawn each container into own tokio::spawn thread
|
||||||
fn update_all_container_stats(&mut self, all_ids: &[(bool, String)]) {
|
fn update_all_container_stats(&mut self, all_ids: &[(bool, ContainerId)]) {
|
||||||
for (is_running, id) in all_ids.iter() {
|
for (is_running, id) in all_ids.iter() {
|
||||||
let docker = Arc::clone(&self.docker);
|
let docker = Arc::clone(&self.docker);
|
||||||
let app_data = Arc::clone(&self.app_data);
|
let app_data = Arc::clone(&self.app_data);
|
||||||
@@ -174,7 +174,7 @@ impl DockerData {
|
|||||||
/// Get all current containers, handle into ContainerItem in the app_data struct rather than here
|
/// Get all current containers, handle into ContainerItem in the app_data struct rather than here
|
||||||
/// Just make sure that items sent are guaranteed to have an id
|
/// Just make sure that items sent are guaranteed to have an id
|
||||||
/// Will ignore any container that contains `oxker` as an entry point
|
/// Will ignore any container that contains `oxker` as an entry point
|
||||||
pub async fn update_all_containers(&mut self) -> Vec<(bool, String)> {
|
pub async fn update_all_containers(&mut self) -> Vec<(bool, ContainerId)> {
|
||||||
let containers = self
|
let containers = self
|
||||||
.docker
|
.docker
|
||||||
.list_containers(Some(ListContainersOptions::<String> {
|
.list_containers(Some(ListContainersOptions::<String> {
|
||||||
@@ -211,7 +211,7 @@ impl DockerData {
|
|||||||
(
|
(
|
||||||
i.state == Some("running".to_owned())
|
i.state == Some("running".to_owned())
|
||||||
|| i.state == Some("restarting".to_owned()),
|
|| i.state == Some("restarting".to_owned()),
|
||||||
id.clone(),
|
ContainerId::from(id.as_str()),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -223,7 +223,7 @@ impl DockerData {
|
|||||||
/// remove if from spawns hashmap when complete
|
/// remove if from spawns hashmap when complete
|
||||||
async fn update_log(
|
async fn update_log(
|
||||||
docker: Arc<Docker>,
|
docker: Arc<Docker>,
|
||||||
id: String,
|
id: ContainerId,
|
||||||
timestamps: bool,
|
timestamps: bool,
|
||||||
since: u64,
|
since: u64,
|
||||||
app_data: Arc<Mutex<AppData>>,
|
app_data: Arc<Mutex<AppData>>,
|
||||||
@@ -232,11 +232,11 @@ impl DockerData {
|
|||||||
let options = Some(LogsOptions::<String> {
|
let options = Some(LogsOptions::<String> {
|
||||||
stdout: true,
|
stdout: true,
|
||||||
timestamps,
|
timestamps,
|
||||||
since: since as i64,
|
since: i64::try_from(since).unwrap_or_default(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut logs = docker.logs(&id, options);
|
let mut logs = docker.logs(id.get(), options);
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
|
||||||
while let Some(value) = logs.next().await {
|
while let Some(value) = logs.next().await {
|
||||||
@@ -252,7 +252,7 @@ impl DockerData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Update all logs, spawn each container into own tokio::spawn thread
|
/// Update all logs, spawn each container into own tokio::spawn thread
|
||||||
fn init_all_logs(&mut self, all_ids: &[(bool, String)]) {
|
fn init_all_logs(&mut self, all_ids: &[(bool, ContainerId)]) {
|
||||||
for (_, id) in all_ids.iter() {
|
for (_, id) in all_ids.iter() {
|
||||||
let docker = Arc::clone(&self.docker);
|
let docker = Arc::clone(&self.docker);
|
||||||
let app_data = Arc::clone(&self.app_data);
|
let app_data = Arc::clone(&self.app_data);
|
||||||
@@ -349,7 +349,7 @@ impl DockerData {
|
|||||||
match message {
|
match message {
|
||||||
DockerMessage::Pause(id) => {
|
DockerMessage::Pause(id) => {
|
||||||
let loading_spin = self.loading_spin(loading_uuid).await;
|
let loading_spin = self.loading_spin(loading_uuid).await;
|
||||||
if docker.pause_container(&id).await.is_err() {
|
if docker.pause_container(id.get()).await.is_err() {
|
||||||
app_data
|
app_data
|
||||||
.lock()
|
.lock()
|
||||||
.set_error(AppError::DockerCommand(DockerControls::Pause));
|
.set_error(AppError::DockerCommand(DockerControls::Pause));
|
||||||
@@ -358,7 +358,7 @@ impl DockerData {
|
|||||||
}
|
}
|
||||||
DockerMessage::Restart(id) => {
|
DockerMessage::Restart(id) => {
|
||||||
let loading_spin = self.loading_spin(loading_uuid).await;
|
let loading_spin = self.loading_spin(loading_uuid).await;
|
||||||
if docker.restart_container(&id, None).await.is_err() {
|
if docker.restart_container(id.get(), None).await.is_err() {
|
||||||
app_data
|
app_data
|
||||||
.lock()
|
.lock()
|
||||||
.set_error(AppError::DockerCommand(DockerControls::Restart));
|
.set_error(AppError::DockerCommand(DockerControls::Restart));
|
||||||
@@ -368,7 +368,7 @@ impl DockerData {
|
|||||||
DockerMessage::Start(id) => {
|
DockerMessage::Start(id) => {
|
||||||
let loading_spin = self.loading_spin(loading_uuid).await;
|
let loading_spin = self.loading_spin(loading_uuid).await;
|
||||||
if docker
|
if docker
|
||||||
.start_container(&id, None::<StartContainerOptions<String>>)
|
.start_container(id.get(), None::<StartContainerOptions<String>>)
|
||||||
.await
|
.await
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
@@ -380,7 +380,7 @@ impl DockerData {
|
|||||||
}
|
}
|
||||||
DockerMessage::Stop(id) => {
|
DockerMessage::Stop(id) => {
|
||||||
let loading_spin = self.loading_spin(loading_uuid).await;
|
let loading_spin = self.loading_spin(loading_uuid).await;
|
||||||
if docker.stop_container(&id, None).await.is_err() {
|
if docker.stop_container(id.get(), None).await.is_err() {
|
||||||
app_data
|
app_data
|
||||||
.lock()
|
.lock()
|
||||||
.set_error(AppError::DockerCommand(DockerControls::Stop));
|
.set_error(AppError::DockerCommand(DockerControls::Stop));
|
||||||
@@ -389,7 +389,7 @@ impl DockerData {
|
|||||||
}
|
}
|
||||||
DockerMessage::Unpause(id) => {
|
DockerMessage::Unpause(id) => {
|
||||||
let loading_spin = self.loading_spin(loading_uuid).await;
|
let loading_spin = self.loading_spin(loading_uuid).await;
|
||||||
if docker.unpause_container(&id).await.is_err() {
|
if docker.unpause_container(id.get()).await.is_err() {
|
||||||
app_data
|
app_data
|
||||||
.lock()
|
.lock()
|
||||||
.set_error(AppError::DockerCommand(DockerControls::Unpause));
|
.set_error(AppError::DockerCommand(DockerControls::Unpause));
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ impl InputHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Handle any keyboard button events
|
/// Handle any keyboard button events
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
async fn button_press(&mut self, key_code: KeyCode) {
|
async fn button_press(&mut self, key_code: KeyCode) {
|
||||||
let show_error = self.app_data.lock().show_error;
|
let show_error = self.app_data.lock().show_error;
|
||||||
let show_info = self.gui_state.lock().show_help;
|
let show_info = self.gui_state.lock().show_help;
|
||||||
|
|||||||
Reference in New Issue
Block a user