Working connection and display of info

This commit is contained in:
2024-01-19 21:12:52 +01:00
parent a7b3ecf178
commit a667c6d98b
18 changed files with 264 additions and 1565 deletions
+16 -23
View File
@@ -1,36 +1,29 @@
use log::{info, trace};
use sieverman::ConnectionInfo;
use tracing::info;
use crate::protocol::BackToFront;
pub(crate) async fn run(
to_frontend_tx: tokio::sync::mpsc::Sender<BackToFront>,
) -> anyhow::Result<()> {
trace!("Starting up sieverman…");
info!("Starting up sieverman…");
info!("Creating connection info");
let info = ConnectionInfo::new("teilgedanken.de", 4190);
let mut connected = info.connect().await.unwrap();
info!("connected to the server");
loop {
match connected.read_introduction().await {
Ok(sieverman::IsComplete::Yes(c)) => {
connected = c;
break;
}
Ok(sieverman::IsComplete::No(c)) => {
trace!("Incomplete data waiting for some time…");
connected = c
}
Err(e) => return Err(anyhow::anyhow!("something went wrong: {}", e)),
};
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
connected.log_buffer().await;
}
trace!("Fully read the introduction:");
connected.log_buffer().await;
connected.log_server_settings().await;
info!("connecting…");
let future_info = info.connect();
info!("waiting for the connection to be established");
let mut connected = match future_info.await {
Ok(v) => v,
Err(e) => {
info!("Failed to connect: {:?}", e);
panic!("Something went wrong");
}
};
info!("Fully read the introduction:");
to_frontend_tx
.send(BackToFront::ServerConnected(
connected.get_server_capabilities(),
connected.get_server_capabilities().clone(),
))
.await
.unwrap();
+43 -42
View File
@@ -1,11 +1,14 @@
use std::{cell::RefCell, fmt::Display, rc::Rc};
use std::{cell::RefCell, rc::Rc};
use crate::__COMPILED_BLUEPRINT_MAP__;
use gtk4::{
glib,
prelude::{ApplicationExt, BoxExt, GtkWindowExt, WidgetExt},
Application, ApplicationWindow, Builder, Label,
prelude::{ApplicationExt, GtkWindowExt},
Application,
};
use log::trace;
use gtk_blueprint::get_blp;
use libadwaita::prelude::{PreferencesGroupExt, PreferencesRowExt};
use tracing::trace;
use crate::protocol::BackToFront;
@@ -25,50 +28,30 @@ fn build_ui(
app: &gtk4::Application,
from_backend_rx: Rc<RefCell<Option<tokio::sync::mpsc::Receiver<BackToFront>>>>,
) {
let action_content_status = gtk4::Box::builder()
.orientation(gtk4::Orientation::Vertical)
.spacing(5)
.build();
let action = gtk4::ActionBar::new();
let status = gtk4::Statusbar::new();
let main_log_server_info = gtk4::Box::builder()
.orientation(gtk4::Orientation::Horizontal)
.hexpand(true)
.vexpand(true)
.halign(gtk4::Align::Fill)
.build();
action_content_status.append(&action);
action_content_status.append(&main_log_server_info);
action_content_status.append(&status);
let log = gtk4::Label::builder().label("Log").hexpand(true).build();
let server_info_content = gtk4::Label::builder().label("Server Info").build();
let server_info_container = gtk4::ScrolledWindow::builder()
.child(&server_info_content)
.width_request(400)
.build();
main_log_server_info.append(&log);
main_log_server_info.append(&server_info_container);
let main_window = gtk4::ApplicationWindow::builder()
.application(app)
.title("Sieverman")
.height_request(400)
.width_request(400)
.child(&action_content_status)
.build();
main_window.present();
let server_info = Rc::new(RefCell::new(server_info_content));
let builder = gtk4::Builder::new();
builder
.add_from_string(get_blp!("gui/main_window.blp"))
.expect("Failed to parse blueprint");
let main_window = builder
.object::<libadwaita::ApplicationWindow>("window")
.unwrap();
let prefrences_group = builder
.object::<libadwaita::PreferencesGroup>("server_settings")
.unwrap();
main_window.set_application(Some(app));
let future = {
let mut data_event_receiver = from_backend_rx.take().expect("data_event_reciver");
async move {
while let Some(event) = data_event_receiver.recv().await {
trace!("data event: {:?}", event);
match event {
BackToFront::ServerConnected(message) => {
server_info
.borrow_mut()
.set_label(&format!("{:#?}", message));
BackToFront::ServerConnected(caps) => {
prefrences_group.add(&row_in_settings("Greeting", &caps.implementation));
prefrences_group
.add(&row_in_settings("Authentication", &caps.sasl.join(",")));
prefrences_group
.add(&row_in_settings("Starttls", &caps.starttls.to_string()));
prefrences_group.add(&row_in_settings("Version", &caps.version));
}
}
}
@@ -78,4 +61,22 @@ fn build_ui(
let c = glib::MainContext::default();
c.spawn_local(future);
main_window.present();
trace!("Window is visible");
}
fn row_in_settings(name: &str, value: &str) -> libadwaita::ActionRow {
let builder = gtk4::Builder::new();
builder
.add_from_string(get_blp!("gui/server_info_row.blp"))
.expect("Failed to parse blueprint");
let row = builder
.object::<libadwaita::ActionRow>("server_info_row")
.unwrap();
row.set_title(name);
let label = builder
.object::<gtk4::Label>("server_info_row_value")
.unwrap();
label.set_label(value);
row
}
+48
View File
@@ -0,0 +1,48 @@
use gtk4::prelude::{ApplicationExt, ApplicationExtManual, GtkWindowExt};
// We're using gtk-builder feature here
use gtk_blueprint::get_blp;
use libadwaita::prelude::PreferencesGroupExt;
gtk_blueprint::gen_blp_map!("gui");
fn main() {
gtk4::init().expect("GTK initialization failed");
libadwaita::init().expect("Adwaita initialization failed");
// Create app
let application = gtk4::Application::builder()
.application_id("de.teilgedanken.sieverman")
.build();
// Init app window and show it
application.connect_activate(|app| {
// You also can parse blueprint with Parser::parse
// and then use it in gtk4::Builder
let builder = gtk4::Builder::new();
builder
.add_from_string(get_blp!("gui/main_window.blp"))
.expect("Failed to parse blueprint");
let window = builder
.object::<libadwaita::ApplicationWindow>("window")
.unwrap();
let settings: libadwaita::PreferencesGroup = builder
.object("server_settings")
.expect("get server settings");
for _ in 0..5 {
let builder = gtk4::Builder::new();
builder
.add_from_string(get_blp!("gui/headerbar.blp"))
.expect("Failed to parse blueprint");
let widget: libadwaita::PreferencesRow = builder
.object("server_info_row")
.expect("Couldn't get widget");
settings.add(&widget);
}
window.set_application(Some(app));
window.present();
});
// Run app
application.run();
}
+1 -1
View File
@@ -1,4 +1,3 @@
use log::info;
use nom::branch::alt;
use nom::bytes::complete::is_not;
use nom::character::is_space;
@@ -12,6 +11,7 @@ use nom::{character, number};
use sieverman::parser::parse_server_config;
use sieverman::{Methods, ServerSettings};
use std::error::Error;
use tracing::info;
fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
@@ -9,7 +9,6 @@
/// that is sensible outside of example code.
use std::sync::Arc;
use log::{error, info, trace};
use managesieve::{Capability, MSResult, Response};
use nom::{error::ParseError, IResult};
use sieverman::parser::parse_server_config;
@@ -23,6 +22,7 @@ use tokio_rustls::{
rustls::{ClientConfig, KeyLogFile, RootCertStore},
TlsConnector,
};
use tracing::{error, info, trace};
#[macro_export]
macro_rules! parse_response {
+2 -2
View File
@@ -1,7 +1,7 @@
use managesieve::Capability;
use managesieve::Capabilities;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum BackToFront {
ServerConnected(Vec<Capability>),
ServerConnected(Capabilities),
}
+18 -3
View File
@@ -1,15 +1,27 @@
mod backend;
mod gui;
pub mod protocol;
use std::{cell::RefCell, rc::Rc, thread};
use std::{cell::RefCell, rc::Rc, thread, time::Duration};
use gtk4::{glib, prelude::ApplicationExtManual as _};
use tracing::{info, trace};
gtk_blueprint::gen_blp_map!("gui");
fn main() -> glib::ExitCode {
env_logger::init();
console_subscriber::ConsoleLayer::builder()
// set how long the console will retain data from completed tasks
.retention(Duration::from_secs(60))
// set the address the server is bound to
.server_addr(([127, 0, 0, 1], 6669))
.init();
gtk4::init().expect("Failed to initialize GTK");
libadwaita::init().expect("Adwaita initialization failed");
let (to_frontent_tx, from_backend_rx) = tokio::sync::mpsc::channel(5);
let _handle = thread::spawn(move || {
info!("Running Backend");
tokio::runtime::Builder::new_current_thread()
.enable_io()
.enable_time()
@@ -21,5 +33,8 @@ fn main() -> glib::ExitCode {
let app = gui::main_window::get_app(Rc::new(RefCell::new(Some(from_backend_rx))));
app.run()
let res = app.run();
trace!("End");
res
}
+61 -34
View File
@@ -1,20 +1,18 @@
use std::{any, net::SocketAddr, sync::Arc, time::Duration};
use std::{sync::Arc, time::Duration};
use log::{error, info, trace};
use managesieve::Capability;
use std::net::ToSocketAddrs;
use managesieve::Capabilities;
use thiserror::Error;
use tokio::{
io::{split, AsyncBufReadExt, BufReader, ReadHalf, WriteHalf},
io::{split, AsyncBufReadExt, BufReader, WriteHalf},
net::TcpStream,
sync::Mutex,
task::JoinHandle,
};
use tokio_rustls::{
client::TlsStream,
rustls::{ClientConfig, KeyLogFile, RootCertStore},
TlsConnector,
};
use tracing::{error, info, trace};
pub mod parser;
@@ -32,6 +30,7 @@ impl ConnectionInfo {
}
}
pub async fn connect(self) -> Result<ConnectionConnected, anyhow::Error> {
info!("connecting to the server");
trace!("Building Cert Store");
let mut root_store = RootCertStore::empty();
root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
@@ -48,11 +47,11 @@ impl ConnectionInfo {
let domain = pki_types::ServerName::try_from(self.domain.clone())?.to_owned();
trace!("Attach the connector");
let stream = connector.connect(domain, stream).await?;
let (reader, mut writer) = split(stream);
let (reader, writer) = split(stream);
let buffer = Arc::new(Mutex::new(String::new()));
let spawned_buffer = buffer.clone();
let join_handle = tokio::spawn(async move {
let _join_handle = tokio::spawn(async move {
let mut buf = String::new();
let mut reader = BufReader::new(reader);
loop {
@@ -67,13 +66,36 @@ impl ConnectionInfo {
}
buf.clear();
};
tokio::time::sleep(Duration::from_millis(50)).await;
}
});
let caps = loop {
let mut buf = buffer.lock().await;
trace!("reading new input:\n{}", buf);
match managesieve::response_capability(&buf.to_string()) {
Ok((rest, caps, resp)) => match resp.tag {
managesieve::OkNoBye::Ok => {
buf.clear();
buf.push_str(rest);
info!("Read the introduction");
break caps;
}
managesieve::OkNoBye::No | managesieve::OkNoBye::Bye => {
trace!("Connection closed!");
//panic!("Invalid Response")
}
},
Err(e) => trace!("(temporary) error: {}", e),
}
tokio::time::sleep(Duration::from_millis(50)).await;
};
trace!("Capabilities read: {:#?}", &caps);
Ok(ConnectionConnected {
info: self,
writer: Arc::new(writer), //server_settings: todo!(),
writer: Arc::new(writer),
buffer,
server_settings: Vec::new(), //join_handle: Arc::new(join_handle),
server_settings: caps,
})
}
}
@@ -85,7 +107,7 @@ pub struct ConnectionConnected {
writer: Arc<WriteHalf<TlsStream<TcpStream>>>,
buffer: Arc<Mutex<String>>,
//pub join_handle: Arc<JoinHandle<()>>,
server_settings: Vec<Capability>,
server_settings: Capabilities,
}
#[derive(Error, Debug)]
@@ -95,7 +117,7 @@ pub enum ReadError {
#[error("The data the server responded was invalid")]
InvalidResponse(#[source] managesieve::Error),
}
#[derive(Debug)]
pub enum IsComplete<T> {
Yes(T),
No(T),
@@ -103,11 +125,12 @@ pub enum IsComplete<T> {
impl ConnectionConnected {
pub async fn log_buffer(&self) {
trace!("Buffer is: \n{}", self.buffer.lock().await)
info!("Buffer is: \n{}", self.buffer.lock().await)
}
pub async fn log_server_settings(&self) {
trace!("Serversettings:\n{:?}", self.server_settings)
info!("Serversettings:\n{:?}", self.server_settings)
}
#[tracing::instrument(name = "gettin the intro")]
pub async fn read_introduction(self) -> Result<IsComplete<Self>, anyhow::Error> {
let Self {
info,
@@ -116,12 +139,11 @@ impl ConnectionConnected {
buffer,
server_settings,
} = self;
tokio::time::sleep(Duration::from_millis(500)).await;
tokio::time::sleep(Duration::from_millis(50)).await;
let mut bf = buffer.lock().await;
let bf_str = bf.clone();
match managesieve::response_capability(&bf_str) {
let response = match managesieve::response_capability(&bf.to_string()) {
Ok((rest, capability, response)) => {
trace!("{:?}", response);
info!("Successfully read the introduction {:?}", response);
bf.clear();
bf.push_str(rest);
drop(bf);
@@ -132,12 +154,15 @@ impl ConnectionConnected {
server_settings: capability,
}))
}
Err(managesieve::Error::IncompleteResponse) => Ok(IsComplete::No(Self {
info,
writer,
buffer: buffer.clone(),
server_settings,
})),
Err(managesieve::Error::IncompleteResponse) => {
trace!("incomplete introduction");
Ok(IsComplete::No(Self {
info,
writer,
buffer: buffer.clone(),
server_settings,
}))
}
Err(managesieve::Error::InvalidResponse) => {
error!("invalid response");
Err(managesieve::Error::InvalidResponse)?
@@ -146,18 +171,20 @@ impl ConnectionConnected {
error!("invalid input");
Err(managesieve::Error::InvalidResponse)?
}
}
}
pub fn get_greeting(&self) -> Option<String> {
for c in self.server_settings.iter() {
if let Capability::Implementation(s) = c {
return Some(s.clone());
Err(managesieve::Error::MissingLine(line)) => {
error!("a capability line was missing: {:?}", line);
Err(managesieve::Error::InvalidResponse)?
}
}
None
};
response
}
pub fn get_server_capabilities(&self) -> Vec<Capability> {
self.server_settings.clone()
pub fn get_greeting(&self) -> String {
self.server_settings.implementation.to_string()
}
pub fn get_server_capabilities(&self) -> &Capabilities {
&self.server_settings
}
}
+1 -1
View File
@@ -1,4 +1,3 @@
use log::{info, trace};
use nom::{
branch::alt,
bytes::complete::is_not,
@@ -11,6 +10,7 @@ use nom::{
sequence::preceded,
IResult,
};
use tracing::trace;
use crate::{parser::utils::key_value, Methods, ServerSettings};