mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
feat(windows): count log files (#2964)
There's a 200 ms delay between each file, for debugging. It's nice to demo how it thinks, but it needs to go behind a fault injection flag or be removed completely before merging. 
This commit is contained in:
1
rust/Cargo.lock
generated
1
rust/Cargo.lock
generated
@@ -2025,6 +2025,7 @@ version = "1.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arboard",
|
||||
"chrono",
|
||||
"clap",
|
||||
"connlib-client-shared",
|
||||
"connlib-shared",
|
||||
|
||||
@@ -12,6 +12,7 @@ tauri-build = { version = "1.5", features = [] }
|
||||
[dependencies]
|
||||
arboard = { version = "3.3.0", default-features = false }
|
||||
anyhow = { version = "1.0" }
|
||||
chrono = { workspace = true }
|
||||
clap = { version = "4.4", features = ["derive", "env"] }
|
||||
connlib-client-shared = { workspace = true }
|
||||
connlib-shared = { workspace = true }
|
||||
@@ -20,7 +21,7 @@ firezone-cli-utils = { workspace = true }
|
||||
ipconfig = "0.3.2"
|
||||
keyring = "2.0.5"
|
||||
ring = "0.17"
|
||||
secrecy.workspace = true
|
||||
secrecy = { workspace = true }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
thiserror = { version = "1.0", default-features = false }
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
|
||||
use crate::client::{self, deep_link, AppLocalDataDir};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use client::settings::{self, AdvancedSettings};
|
||||
use client::{
|
||||
logging,
|
||||
settings::{self, AdvancedSettings},
|
||||
};
|
||||
use connlib_client_shared::file_logger;
|
||||
use connlib_shared::messages::ResourceId;
|
||||
use secrecy::{ExposeSecret, SecretString};
|
||||
@@ -79,9 +82,10 @@ pub(crate) fn run(params: client::GuiParams) -> Result<()> {
|
||||
}
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
logging::clear_logs,
|
||||
logging::export_logs,
|
||||
logging::start_stop_log_counting,
|
||||
settings::apply_advanced_settings,
|
||||
settings::clear_logs,
|
||||
settings::export_logs,
|
||||
settings::get_advanced_settings,
|
||||
])
|
||||
.system_tray(tray)
|
||||
@@ -205,6 +209,7 @@ pub(crate) enum ControllerRequest {
|
||||
GetAdvancedSettings(oneshot::Sender<AdvancedSettings>),
|
||||
SchemeRequest(url::Url),
|
||||
SignIn,
|
||||
StartStopLogCounting(bool),
|
||||
SignOut,
|
||||
UpdateResources(Vec<connlib_client_shared::ResourceDescription>),
|
||||
}
|
||||
@@ -395,6 +400,7 @@ async fn run_controller(
|
||||
.await
|
||||
.context("couldn't create Controller")?;
|
||||
|
||||
let mut log_counting_task = None;
|
||||
let mut resources: Vec<ResourceDisplay> = vec![];
|
||||
|
||||
tracing::debug!("GUI controller main loop start");
|
||||
@@ -409,7 +415,7 @@ async fn run_controller(
|
||||
let mut clipboard = arboard::Clipboard::new()?;
|
||||
clipboard.set_text(&res.pastable)?;
|
||||
}
|
||||
Req::ExportLogs(file_path) => settings::export_logs_to(file_path).await?,
|
||||
Req::ExportLogs(file_path) => logging::export_logs_to(file_path).await?,
|
||||
Req::GetAdvancedSettings(tx) => {
|
||||
tx.send(controller.advanced_settings.clone()).ok();
|
||||
}
|
||||
@@ -441,6 +447,19 @@ async fn run_controller(
|
||||
None,
|
||||
)?;
|
||||
}
|
||||
Req::StartStopLogCounting(enable) => {
|
||||
if enable {
|
||||
if log_counting_task.is_none() {
|
||||
let app = app.clone();
|
||||
log_counting_task = Some(tokio::spawn(logging::count_logs(app)));
|
||||
tracing::debug!("started log counting");
|
||||
}
|
||||
} else if let Some(t) = log_counting_task {
|
||||
t.abort();
|
||||
log_counting_task = None;
|
||||
tracing::debug!("cancelled log counting");
|
||||
}
|
||||
}
|
||||
Req::SignOut => {
|
||||
keyring_entry()?.delete_password()?;
|
||||
if let Some(mut session) = controller.connlib_session.take() {
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
//! Separate module to contain all the `use` statements for setting up logging
|
||||
//! Everything for logging to files, zipping up the files for export, and counting the files
|
||||
|
||||
use crate::client::gui::{ControllerRequest, CtlrTx, Managed};
|
||||
use anyhow::Result;
|
||||
use connlib_client_shared::file_logger;
|
||||
use std::{path::Path, str::FromStr};
|
||||
use serde::Serialize;
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
result::Result as StdResult,
|
||||
str::FromStr,
|
||||
time::Duration,
|
||||
};
|
||||
use tauri::Manager;
|
||||
use tokio::fs;
|
||||
use tracing::subscriber::set_global_default;
|
||||
use tracing_log::LogTracer;
|
||||
use tracing_subscriber::{fmt, layer::SubscriberExt, reload, EnvFilter, Layer, Registry};
|
||||
@@ -28,3 +37,88 @@ pub(crate) fn setup(log_filter: &str) -> Result<Handles> {
|
||||
_reloader: reloader,
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) async fn start_stop_log_counting(
|
||||
managed: tauri::State<'_, Managed>,
|
||||
enable: bool,
|
||||
) -> StdResult<(), String> {
|
||||
managed
|
||||
.ctlr_tx
|
||||
.send(ControllerRequest::StartStopLogCounting(enable))
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) async fn clear_logs() -> StdResult<(), String> {
|
||||
clear_logs_inner().await.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) async fn export_logs(managed: tauri::State<'_, Managed>) -> StdResult<(), String> {
|
||||
export_logs_inner(managed.ctlr_tx.clone())
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
pub(crate) async fn clear_logs_inner() -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Pops up the "Save File" dialog
|
||||
pub(crate) async fn export_logs_inner(ctlr_tx: CtlrTx) -> Result<()> {
|
||||
let now = chrono::Local::now();
|
||||
let datetime_string = now.format("%Y_%m_%d-%H-%M");
|
||||
let filename = format!("connlib-{datetime_string}.zip");
|
||||
|
||||
tauri::api::dialog::FileDialogBuilder::new()
|
||||
.add_filter("Zip", &["zip"])
|
||||
.set_file_name(&filename)
|
||||
.save_file(move |file_path| match file_path {
|
||||
None => {}
|
||||
Some(x) => {
|
||||
// blocking_send here because we're in a sync callback within Tauri somewhere
|
||||
ctlr_tx
|
||||
.blocking_send(ControllerRequest::ExportLogs(x))
|
||||
.unwrap()
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Exports logs to a zip file
|
||||
pub(crate) async fn export_logs_to(file_path: PathBuf) -> Result<()> {
|
||||
tracing::trace!("Exporting logs to {file_path:?}");
|
||||
|
||||
let mut entries = fs::read_dir("logs").await?;
|
||||
while let Some(entry) = entries.next_entry().await? {
|
||||
let _path = entry.path();
|
||||
// TODO: Actually add log files to a zip file
|
||||
}
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
// TODO: Somehow signal back to the GUI to unlock the log buttons when the export completes, or errors out
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
struct FileCount {
|
||||
files: u64,
|
||||
bytes: u64,
|
||||
}
|
||||
|
||||
pub(crate) async fn count_logs(app: tauri::AppHandle) -> Result<()> {
|
||||
let mut dir = fs::read_dir("logs").await?;
|
||||
let mut files: u64 = 0;
|
||||
let mut bytes: u64 = 0;
|
||||
while let Some(entry) = dir.next_entry().await? {
|
||||
// TODO: Remove sleep before merging
|
||||
// This is useful for debugging to show how the GUI thinks and make sure nothing else blocks on this
|
||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||
let md = entry.metadata().await?;
|
||||
files += 1;
|
||||
bytes += md.len();
|
||||
app.emit_all("file_count_progress", FileCount { files, bytes })?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -55,18 +55,6 @@ pub(crate) async fn apply_advanced_settings(
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) async fn clear_logs() -> StdResult<(), String> {
|
||||
clear_logs_inner().await.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) async fn export_logs(managed: tauri::State<'_, Managed>) -> StdResult<(), String> {
|
||||
export_logs_inner(managed.ctlr_tx.clone())
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) async fn get_advanced_settings(
|
||||
managed: tauri::State<'_, Managed>,
|
||||
@@ -105,32 +93,3 @@ pub(crate) async fn load_advanced_settings(app: &tauri::AppHandle) -> Result<Adv
|
||||
let settings = serde_json::from_str(&text)?;
|
||||
Ok(settings)
|
||||
}
|
||||
|
||||
pub(crate) async fn clear_logs_inner() -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub(crate) async fn export_logs_inner(ctlr_tx: gui::CtlrTx) -> Result<()> {
|
||||
tauri::api::dialog::FileDialogBuilder::new()
|
||||
.add_filter("Zip", &["zip"])
|
||||
.save_file(move |file_path| match file_path {
|
||||
None => {}
|
||||
Some(x) => ctlr_tx
|
||||
.blocking_send(ControllerRequest::ExportLogs(x))
|
||||
.unwrap(),
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn export_logs_to(file_path: PathBuf) -> Result<()> {
|
||||
tracing::trace!("Exporting logs to {file_path:?}");
|
||||
|
||||
let mut entries = tokio::fs::read_dir("logs").await?;
|
||||
while let Some(entry) = entries.next_entry().await? {
|
||||
let path = entry.path();
|
||||
tracing::trace!("Export {path:?}");
|
||||
}
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
// TODO: Somehow signal back to the GUI to unlock the log buttons when the export completes, or errors out
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
<button type="button" id="export-logs-btn">Export Logs</button>
|
||||
<button type="button" id="clear-logs-btn">Clear Logs</button>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="log-count-output"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tab_advanced" class="tabcontent">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
let auth_base_url_input;
|
||||
let api_url_input;
|
||||
let log_count_output;
|
||||
let log_filter_input;
|
||||
let reset_advanced_settings_btn;
|
||||
let apply_advanced_settings_btn;
|
||||
@@ -11,6 +12,7 @@ const querySel = function(id) {
|
||||
};
|
||||
|
||||
const { invoke } = window.__TAURI__.tauri;
|
||||
const { listen } = window.__TAURI__.event;
|
||||
|
||||
// Lock the UI when we're saving to disk, since disk writes are technically async.
|
||||
// Parameters:
|
||||
@@ -116,12 +118,21 @@ function openTab(evt, tabName) {
|
||||
document.getElementById(tabName).style.display = "block";
|
||||
// TODO: There's a better way to do this
|
||||
evt.currentTarget.className += " active";
|
||||
|
||||
invoke("start_stop_log_counting", {"enable": tabName == "tab_logs"})
|
||||
.then(() => {
|
||||
// Good
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
async function setup() {
|
||||
// Advanced tab
|
||||
auth_base_url_input = querySel("#auth-base-url-input");
|
||||
api_url_input = querySel("#api-url-input");
|
||||
log_count_output = querySel("#log-count-output");
|
||||
log_filter_input = querySel("#log-filter-input");
|
||||
reset_advanced_settings_btn = querySel("#reset-advanced-settings-btn");
|
||||
apply_advanced_settings_btn = querySel("#apply-advanced-settings-btn");
|
||||
@@ -142,8 +153,16 @@ window.addEventListener("DOMContentLoaded", () => {
|
||||
clear_logs();
|
||||
});
|
||||
|
||||
await listen("file_count_progress", (event) => {
|
||||
const pl = event.payload;
|
||||
const megabytes = Math.round(pl.bytes / 100000) / 10;
|
||||
log_count_output.innerText = `${pl.files} files, ${megabytes} MB`;
|
||||
});
|
||||
|
||||
// TODO: Why doesn't this open the Advanced tab by default?
|
||||
querySel("#tab_advanced").click();
|
||||
|
||||
get_advanced_settings().await;
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener("DOMContentLoaded",setup);
|
||||
|
||||
Reference in New Issue
Block a user