From 3d509b0afcbed2f06c4088eec21e2974cc5500f2 Mon Sep 17 00:00:00 2001 From: Ward from fusion-voyager-3 Date: Wed, 10 Jul 2024 12:50:48 +0300 Subject: [PATCH] installer sockets --- .idea/workspace.xml | 26 ++--- src/bin/apt/apt_full_upgrade/main.rs | 67 +++++++++++- src/bin/gui/apt_update_page/mod.rs | 93 +---------------- src/bin/gui/apt_update_page/process.rs | 115 ++++++++++++++++++++- src/lib/apt_install_progress_socket/mod.rs | 104 +++++++++++++++++++ src/lib/lib.rs | 1 + src/lib/pika_unixsocket_tools/mod.rs | 32 +++++- 7 files changed, 326 insertions(+), 112 deletions(-) create mode 100644 src/lib/apt_install_progress_socket/mod.rs diff --git a/.idea/workspace.xml b/.idea/workspace.xml index f28b1c5..ab4c414 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -8,22 +8,13 @@ - - - - + - - - - - - - - - - - + + + + + + @@ -146,7 +138,7 @@ - + diff --git a/src/bin/apt/apt_full_upgrade/main.rs b/src/bin/apt/apt_full_upgrade/main.rs index e71fdf5..d80cecd 100644 --- a/src/bin/apt/apt_full_upgrade/main.rs +++ b/src/bin/apt/apt_full_upgrade/main.rs @@ -1 +1,66 @@ -fn main() {} \ No newline at end of file +use rust_apt::new_cache; +use rust_apt::progress::{AcquireProgress, InstallProgress}; +use tokio::runtime::Runtime; +use pika_unixsocket_tools::apt_update_progress_socket::AptUpdateProgressSocket; +use pika_unixsocket_tools::apt_install_progress_socket::AptInstallProgressSocket; +use pika_unixsocket_tools::pika_unixsocket_tools::*; + +fn main() { + let cache = new_cache!().unwrap(); + let percent_socket_path = "/tmp/pika_apt_upgrade_percent.sock"; + let status_socket_path = "/tmp/pika_apt_upgrade_status.sock"; + + let pkg = cache.get("neovim").unwrap(); + let mut acquire_progress = AcquireProgress::new(AptUpdateProgressSocket::new( + percent_socket_path, + status_socket_path, + )); + let mut install_progress = InstallProgress::new(AptInstallProgressSocket::new( + percent_socket_path, + status_socket_path, + )); + + pkg.mark_install(true, true); + pkg.protect(); + cache.resolve(true).unwrap(); + + match cache.get_archives(&mut acquire_progress) { + Ok(_) => { + Runtime::new() + .unwrap() + .block_on(send_successful_to_socket(percent_socket_path)); + Runtime::new() + .unwrap() + .block_on(send_successful_to_socket(status_socket_path)); + } + Err(e) => { + Runtime::new() + .unwrap() + .block_on(send_failed_to_socket(percent_socket_path)); + Runtime::new() + .unwrap() + .block_on(send_failed_to_socket(status_socket_path)); + panic!("{}", e.to_string()) + } + }; + + match cache.do_install(&mut install_progress) { + Ok(_) => { + Runtime::new() + .unwrap() + .block_on(send_successful_to_socket(percent_socket_path)); + Runtime::new() + .unwrap() + .block_on(send_successful_to_socket(status_socket_path)); + } + Err(e) => { + Runtime::new() + .unwrap() + .block_on(send_failed_to_socket(percent_socket_path)); + Runtime::new() + .unwrap() + .block_on(send_failed_to_socket(status_socket_path)); + panic!("{}", e.to_string()) + } + }; +} \ No newline at end of file diff --git a/src/bin/gui/apt_update_page/mod.rs b/src/bin/gui/apt_update_page/mod.rs index 6d94f4a..14c3f85 100644 --- a/src/bin/gui/apt_update_page/mod.rs +++ b/src/bin/gui/apt_update_page/mod.rs @@ -53,13 +53,13 @@ pub fn apt_update_page( thread::spawn(move || { Runtime::new() .unwrap() - .block_on(update_percent_socket_server(update_percent_sender)); + .block_on(start_socket_server(update_percent_sender, "/tmp/pika_apt_update_percent.sock")); }); thread::spawn(move || { Runtime::new() .unwrap() - .block_on(update_status_socket_server(update_status_sender)); + .block_on(start_socket_server(update_status_sender, "/tmp/pika_apt_update_status.sock")); }); thread::spawn(move || { @@ -387,92 +387,3 @@ fn set_all_apt_row_marks_to(parent_listbox: &impl IsA, value: bool) { child_counter = next_child } } - -async fn update_percent_socket_server(buffer_sender: async_channel::Sender) { - // Path to the Unix socket file - let socket_path = "/tmp/pika_apt_update_percent.sock"; - - // Remove the socket file if it already exists - if Path::new(socket_path).exists() { - fs::remove_file(socket_path).expect("Could not remove existing socket file"); - } - - // Bind the Unix listener to the socket path - let listener = UnixListener::bind(socket_path).expect("Could not bind"); - - println!("Server listening on {}", socket_path); - - // Loop to accept incoming connections - loop { - // Accept an incoming connection - match listener.accept().await { - Ok((stream, _)) => { - // Handle the connection in a separate task - task::spawn(handle_client(stream, buffer_sender.clone())); - } - Err(e) => { - // Print error message if a connection fails - eprintln!("Connection failed: {}", e); - } - } - } -} - -async fn update_status_socket_server(buffer_sender: async_channel::Sender) { - // Path to the Unix socket file - let socket_path = "/tmp/pika_apt_update_status.sock"; - - // Remove the socket file if it already exists - if Path::new(socket_path).exists() { - fs::remove_file(socket_path).expect("Could not remove existing socket file"); - } - - // Bind the Unix listener to the socket path - let listener = UnixListener::bind(socket_path).expect("Could not bind"); - - println!("Server listening on {}", socket_path); - - // Loop to accept incoming connections - loop { - // Accept an incoming connection - match listener.accept().await { - Ok((stream, _)) => { - // Handle the connection in a separate task - task::spawn(handle_client(stream, buffer_sender.clone())); - } - Err(e) => { - // Print error message if a connection fails - eprintln!("Connection failed: {}", e); - } - } - } -} -async fn get_upgradable_socket_server(buffer_sender: async_channel::Sender) { - // Path to the Unix socket file - let socket_path = "/tmp/pika_apt_get_upgradable.sock"; - - // Remove the socket file if it already exists - if Path::new(socket_path).exists() { - fs::remove_file(socket_path).expect("Could not remove existing socket file"); - } - - // Bind the Unix listener to the socket path - let listener = UnixListener::bind(socket_path).expect("Could not bind"); - - println!("Server listening on {}", socket_path); - - // Loop to accept incoming connections - loop { - // Accept an incoming connection - match listener.accept().await { - Ok((stream, _)) => { - // Handle the connection in a separate task - task::spawn(handle_client(stream, buffer_sender.clone())); - } - Err(e) => { - // Print error message if a connection fails - eprintln!("Connection failed: {}", e); - } - } - } -} diff --git a/src/bin/gui/apt_update_page/process.rs b/src/bin/gui/apt_update_page/process.rs index a8ef5fe..abea871 100644 --- a/src/bin/gui/apt_update_page/process.rs +++ b/src/bin/gui/apt_update_page/process.rs @@ -5,8 +5,11 @@ use gtk::glib::*; use gtk::*; use pretty_bytes::converter::convert; use serde_json::{Value}; -use std::{fs::*}; +use std::{fs::*, thread}; use std::path::Path; +use std::process::Command; +use tokio::runtime::Runtime; +use pika_unixsocket_tools::pika_unixsocket_tools::start_socket_server; struct AptChangesInfo { package_count: u64, @@ -174,7 +177,115 @@ fn apt_confirm_window(excluded_updates_vec: &Vec, window: adw::Applicati std::fs::write(json_file_path, serde_json::to_string_pretty(&excluded_updates_values_json).unwrap()).expect("Failed to write to json file"); } - apt_confirm_dialog.present(); + //apt_confirm_dialog.present(); + apt_full_upgrade_from_socket(window); +} + +fn apt_full_upgrade_from_socket(window: adw::ApplicationWindow) { + let (upgrade_percent_sender, upgrade_percent_receiver) = async_channel::unbounded::(); + let upgrade_percent_sender = upgrade_percent_sender.clone(); + let (upgrade_status_sender, upgrade_status_receiver) = async_channel::unbounded::(); + let upgrade_status_sender = upgrade_status_sender.clone(); + let upgrade_status_sender_clone0 = upgrade_status_sender.clone(); + + thread::spawn(move || { + Runtime::new() + .unwrap() + .block_on(start_socket_server(upgrade_percent_sender, "/tmp/pika_apt_upgrade_percent.sock")); + }); + + thread::spawn(move || { + Runtime::new() + .unwrap() + .block_on(start_socket_server(upgrade_status_sender, "/tmp/pika_apt_upgrade_status.sock")); + }); + + thread::spawn(move || { + let apt_upgrade_command = Command::new("pkexec") + .args(["/home/ward/RustroverProjects/pika-idk-manager/target/debug/apt_full_upgrade"]) + .status() + .unwrap(); + match apt_upgrade_command.code().unwrap() { + 0 => { + upgrade_status_sender_clone0 + .send_blocking("FN_OVERRIDE_SUCCESSFUL".to_owned()) + .unwrap() + } + 53 => {} + _ => { + upgrade_status_sender_clone0 + .send_blocking(t!("upgrade_status_error_perms").to_string()) + .unwrap(); + upgrade_status_sender_clone0 + .send_blocking("FN_OVERRIDE_FAILED".to_owned()) + .unwrap() + } + } + }); + + let apt_upgrade_dialog_child_box = gtk::Box::builder() + .orientation(Orientation::Vertical) + .build(); + + let apt_upgrade_dialog_progress_bar = gtk::ProgressBar::builder() + .show_text(true) + .hexpand(true) + .build(); + + let apt_upgrade_dialog_spinner = gtk::Spinner::builder() + .hexpand(true) + .valign(Align::Start) + .halign(Align::Center) + .spinning(true) + .height_request(128) + .width_request(128) + .build(); + + apt_upgrade_dialog_child_box.append(&apt_upgrade_dialog_spinner); + apt_upgrade_dialog_child_box.append(&apt_upgrade_dialog_progress_bar); + + let apt_upgrade_dialog = adw::MessageDialog::builder() + .transient_for(&window) + .extra_child(&apt_upgrade_dialog_child_box) + .heading(t!("apt_upgrade_dialog_heading")) + .hide_on_close(true) + .width_request(500) + .build(); + + let upgrade_percent_server_context = MainContext::default(); + // The main loop executes the asynchronous block + upgrade_percent_server_context.spawn_local(clone!(@weak apt_upgrade_dialog_progress_bar, @weak apt_upgrade_dialog => async move { + while let Ok(state) = upgrade_percent_receiver.recv().await { + match state.as_ref() { + "FN_OVERRIDE_SUCCESSFUL" => {} + _ => { + apt_upgrade_dialog_progress_bar.set_fraction(state.parse::().unwrap()/100.0) + } + } + } + })); + + let upgrade_status_server_context = MainContext::default(); + // The main loop executes the asynchronous block + upgrade_status_server_context.spawn_local( + clone!(@weak apt_upgrade_dialog, @weak apt_upgrade_dialog_child_box => async move { + while let Ok(state) = upgrade_status_receiver.recv().await { + match state.as_ref() { + "FN_OVERRIDE_SUCCESSFUL" => { + apt_upgrade_dialog.close(); + } + "FN_OVERRIDE_FAILED" => { + apt_upgrade_dialog_child_box.set_visible(false); + apt_upgrade_dialog.set_title(Some(&t!("apt_upgrade_dialog_status_failed").to_string())); + apt_upgrade_dialog.set_response_enabled("apt_upgrade_dialog_ok", true); + } + _ => apt_upgrade_dialog.set_body(&state) + } + } + }), + ); + + apt_upgrade_dialog.present(); } fn create_color_badge( diff --git a/src/lib/apt_install_progress_socket/mod.rs b/src/lib/apt_install_progress_socket/mod.rs new file mode 100644 index 0000000..999e51b --- /dev/null +++ b/src/lib/apt_install_progress_socket/mod.rs @@ -0,0 +1,104 @@ +use crate::pika_unixsocket_tools::*; +use rust_apt::progress::{DynAcquireProgress, DynInstallProgress}; +use rust_apt::raw::{AcqTextStatus, ItemDesc, PkgAcquire}; +use std::process::exit; +use tokio::io::{AsyncWriteExt}; +use tokio::net::UnixStream; +use tokio::runtime::Runtime; + +pub struct AptInstallProgressSocket<'a> { + pkgname: String, + steps_done: u64, + total_steps: u64, + action: String, + percent_socket_path: &'a str, + status_socket_path: &'a str, +} + +impl<'a> AptInstallProgressSocket<'a> { + /// Returns a new default progress instance. + pub fn new(percent_socket_path: &'a str, status_socket_path: &'a str) -> Self { + let mut progress = Self { + pkgname: String::new(), + steps_done: 0, + total_steps: 0, + action: String::new(), + percent_socket_path: percent_socket_path, + status_socket_path: status_socket_path, + }; + progress + } +} + +impl<'a> DynInstallProgress for AptInstallProgressSocket<'a> { + fn status_changed( + &mut self, + pkgname: String, + steps_done: u64, + total_steps: u64, + action: String + ) { + let progress_percent: f32 = + (steps_done as f32 * 100.0) / total_steps as f32; + Runtime::new().unwrap().block_on(send_progress_percent( + progress_percent, + self.percent_socket_path, + )); + Runtime::new().unwrap().block_on(send_progress_status( + &action, + self.status_socket_path, + )); + } + + fn error( + &mut self, + pkgname: String, + steps_done: u64, + total_steps: u64, + error: String + ) { + let message = format!( + "dpkg failure on {}: {}", + pkgname, + error + ); + eprintln!("{}", &message); + Runtime::new() + .unwrap() + .block_on(send_progress_status(&message, self.status_socket_path)); + Runtime::new() + .unwrap() + .block_on(send_failed_to_socket(self.percent_socket_path)); + Runtime::new() + .unwrap() + .block_on(send_failed_to_socket(self.status_socket_path)); + exit(53) + } +} + +async fn send_progress_percent(progress_f32: f32, socket_path: &str) { + // Connect to the Unix socket + let mut stream = UnixStream::connect(socket_path) + .await + .expect("Could not connect to server"); + + let message = progress_f32.to_string(); + // Send the message to the server + stream + .write_all(message.as_bytes()) + .await + .expect("Failed to write to stream"); +} + +async fn send_progress_status(message: &str, socket_path: &str) { + // Connect to the Unix socket + let mut stream = UnixStream::connect(socket_path) + .await + .expect("Could not connect to server"); + + // Send the message to the server + stream + .write_all(message.as_bytes()) + .await + .expect("Failed to write to stream"); +} diff --git a/src/lib/lib.rs b/src/lib/lib.rs index 22816ae..98c2e73 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -1,2 +1,3 @@ pub mod pika_unixsocket_tools; +pub mod apt_install_progress_socket; pub mod apt_update_progress_socket; \ No newline at end of file diff --git a/src/lib/pika_unixsocket_tools/mod.rs b/src/lib/pika_unixsocket_tools/mod.rs index d8da124..ba37e9c 100644 --- a/src/lib/pika_unixsocket_tools/mod.rs +++ b/src/lib/pika_unixsocket_tools/mod.rs @@ -1,5 +1,8 @@ +use std::fs; +use std::path::Path; use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::net::UnixStream; +use tokio::net::{UnixListener, UnixStream}; +use tokio::task; pub async fn send_successful_to_socket(socket_path: &str) { // Connect to the Unix socket @@ -50,3 +53,30 @@ pub async fn handle_client(mut stream: UnixStream, buffer_sender: async_channel: } } } + +pub async fn start_socket_server(buffer_sender: async_channel::Sender, socket_path: &str) { + // Remove the socket file if it already exists + if Path::new(socket_path).exists() { + fs::remove_file(socket_path).expect("Could not remove existing socket file"); + } + + // Bind the Unix listener to the socket path + let listener = UnixListener::bind(socket_path).expect("Could not bind"); + + println!("Server listening on {}", socket_path); + + // Loop to accept incoming connections + loop { + // Accept an incoming connection + match listener.accept().await { + Ok((stream, _)) => { + // Handle the connection in a separate task + task::spawn(handle_client(stream, buffer_sender.clone())); + } + Err(e) => { + // Print error message if a connection fails + eprintln!("Connection failed: {}", e); + } + } + } +} \ No newline at end of file