From f9561f288309773c1549e8a983d5911b0c00420d Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Sat, 1 Apr 2023 16:10:45 +0300 Subject: [PATCH] Add connect and disconnect buttons --- src/app.rs | 176 +++++++++++++++++++++++++++++++++++++++++++++++++--- src/main.rs | 24 ++++--- src/ubus.rs | 6 +- 3 files changed, 187 insertions(+), 19 deletions(-) diff --git a/src/app.rs b/src/app.rs index 3d567a0..47a34bf 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,11 +1,124 @@ +use std::{ + default, + net::{SocketAddr, SocketAddrV4, ToSocketAddrs}, + sync::mpsc::{Receiver, Sender}, +}; + +use anyhow::{Error, Result}; +use async_ssh2_lite::{AsyncIoTcpStream, AsyncSession}; use eframe::CreationContext; +use serde::de::IntoDeserializer; +pub enum AsyncEvent { + Connect(Result>), + Disconnect(Result<()>) +} -#[derive(Default)] -pub struct App; +pub struct App { + address: String, + port: u16, + username: String, + password: String, + session: Option>, + + is_connecting: bool, + is_disconnecting: bool, + + tx: Sender, + rx: Receiver, +} + +impl Default for App { + fn default() -> Self { + let (tx, rx) = std::sync::mpsc::channel(); + + Self { + address: "172.24.224.1".into(), //"192.168.1.1".to_owned(), + port: 22, + username: "root".to_owned(), + password: "admin01".to_owned(), + session: None, + + is_connecting: false, + is_disconnecting: false, + + tx, + rx, + } + } +} + +async fn connect(socket_addr: A, username: String, password: String) -> Result> +where + A: Into, +{ + let mut session = AsyncSession::::connect(socket_addr, None).await?; + session.handshake().await?; + session.userauth_password(&username, &password).await?; + return Ok(session); +} + +async fn disconnect(session: AsyncSession) -> Result<()> { + session.disconnect(Some(ssh2::DisconnectCode::ByApplication), "Disconnect", Some("en")).await?; + Ok(()) +} impl App { - pub fn init(&mut self, _cc: &CreationContext) { + pub fn init(&mut self, _cc: &CreationContext) {} + + fn handle_connect_event(&mut self, result: Result>) { + self.is_connecting = false; + match result { + Ok(session) => { + self.session = Some(session) + }, + Err(_) => todo!(), + } + } + + fn handle_disconnect_event(&mut self, result: Result<()>) { + self.is_disconnecting = false; + + if let Err(err) = result { + todo!() + } + } + + fn handle_events(&mut self, ctx: &egui::Context) { + if let Ok(event) = self.rx.try_recv() { + match event { + AsyncEvent::Connect(result) => self.handle_connect_event(result), + AsyncEvent::Disconnect(result) => self.handle_disconnect_event(result), + } + } + } + + fn start_connect(&mut self, socket_addr: A, username: String, password: String) + where + A: Into, + { + if self.session.is_some() { return; } + + self.is_connecting = true; + let tx = self.tx.clone(); + let socket_addr = socket_addr.into(); + tokio::spawn(async move { + let result = connect(socket_addr, username, password).await; + tx.send(AsyncEvent::Connect(result)).expect("Failed to send event"); + }); + } + + fn start_disconnect(&mut self) { + if self.session.is_none() { return; } + + self.is_disconnecting = true; + let tx = self.tx.clone(); + let session = self.session.clone().unwrap(); + self.session = None; + tokio::spawn(async move { + let result = disconnect(session).await; + tx.send(AsyncEvent::Disconnect(result)).expect("Failed to send event"); + }); } } @@ -13,9 +126,58 @@ impl eframe::App for App { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { use egui::*; - egui::CentralPanel::default() - .show(ctx, |ui| { - ui.label("Hello World!"); + self.handle_events(ctx); + + egui::CentralPanel::default().show(ctx, |ui| { + egui::SidePanel::left("left_panel") + .resizable(true) + .default_width(150.0) + .width_range(80.0..=200.0) + .show_inside(ui, |ui| { + ui.vertical_centered(|ui| { + ui.heading("Left Panel"); + }); + egui::ScrollArea::vertical().show(ui, |ui| { + ui.label("Foo"); + }); + }); + + egui::SidePanel::right("right_panel") + .resizable(true) + .default_width(150.0) + .width_range(80.0..=200.0) + .show_inside(ui, |ui| { + ui.vertical_centered(|ui| { + ui.heading("Right Panel"); + }); + egui::ScrollArea::vertical().show(ui, |ui| { + ui.text_edit_singleline(&mut self.address); + // TODO: ui.text_edit_singleline(&mut self.port); + ui.text_edit_singleline(&mut self.username); + ui.text_edit_singleline(&mut self.password); + if self.is_connecting { + ui.button("Connecting..."); + } else if self.session.is_none() { + if ui.button("Connect").clicked() { + let socket_addr = SocketAddrV4::new(self.address.parse().unwrap(), self.port); + self.start_connect(socket_addr, self.username.clone(), self.password.clone()); + } + } else { + if ui.button("Disconnect").clicked() { + self.start_disconnect() + } + } + }); + }); + + egui::CentralPanel::default().show_inside(ui, |ui| { + ui.vertical_centered(|ui| { + ui.heading("Central Panel"); + }); + egui::ScrollArea::vertical().show(ui, |ui| { + ui.label("foo"); + }); + }); }); } -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index f2916a1..4455175 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,27 @@ #[cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release -use std::{net::ToSocketAddrs, thread}; +use std::{net::ToSocketAddrs}; use anyhow::Result; -use smol::{channel, block_on}; +use smol::channel; use async_ssh2_lite::{AsyncSession}; use app::App; +use tokio::runtime::Runtime; use ubus::MonitorEvent; -use crate::ubus::{Ubus, ListenEvent, MonitorDir, MonitorEventType}; +use crate::ubus::Ubus; mod app; mod ubus; mod async_line_reader; -#[tokio::main] -async fn main() -> Result<()> { +// TODO: Save config to file + +fn main() { + let rt = Runtime::new().expect("Unable to create Runtime"); + + let _enter = rt.enter(); + + /* let address = "172.24.224.1:22"; let username = "root"; let password = "admin01"; @@ -44,8 +51,8 @@ async fn main() -> Result<()> { let e = rx.recv().await?; dbg!(e); } + */ - /* let mut native_options = eframe::NativeOptions::default(); native_options.decorated = true; native_options.resizable = true; @@ -58,9 +65,6 @@ async fn main() -> Result<()> { app.init(cc); Box::new(app) }) - ) - */ - - Ok(()) + ).expect("Unable to create window"); } diff --git a/src/ubus.rs b/src/ubus.rs index 5013ff5..b7ac9a0 100644 --- a/src/ubus.rs +++ b/src/ubus.rs @@ -1,8 +1,8 @@ -use std::{io::Read, borrow::Cow, net::TcpStream, str::FromStr, any}; +use std::{borrow::Cow, net::TcpStream, str::FromStr}; use async_ssh2_lite::AsyncSession; use lazy_regex::regex_captures; -use serde_json::{Value, json}; +use serde_json::Value; use shell_escape::unix::escape; use hex::FromHex; use anyhow::{Result, bail, anyhow}; @@ -11,6 +11,8 @@ use thiserror::Error; use crate::async_line_reader::AsyncLineReader; +// TODO: Add tests + pub struct Ubus { session: AsyncSession> }