Files
notedeck/crates/notedeck_chrome/src/notedeck.rs
kernelkind 2973a0c6c5 appease clippy
Signed-off-by: kernelkind <kernelkind@gmail.com>
2025-08-25 10:31:42 -04:00

249 lines
7.1 KiB
Rust

#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
// hide console window on Windows in release
#[cfg(feature = "memory")]
use re_memory::AccountingAllocator;
#[cfg(feature = "memory")]
#[global_allocator]
static GLOBAL: AccountingAllocator<std::alloc::System> =
AccountingAllocator::new(std::alloc::System);
use notedeck::{DataPath, DataPathType, Notedeck};
use notedeck_chrome::{setup::generate_native_options, Chrome};
use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::EnvFilter;
fn setup_logging(path: &DataPath) -> Option<WorkerGuard> {
#[allow(unused_variables)] // need guard to live for lifetime of program
let (maybe_non_blocking, maybe_guard) = {
let log_path = path.path(DataPathType::Log);
// Setup logging to file
use tracing_appender::{
non_blocking,
rolling::{RollingFileAppender, Rotation},
};
let file_appender = RollingFileAppender::new(
Rotation::DAILY,
log_path,
format!("notedeck-{}.log", env!("CARGO_PKG_VERSION")),
);
let (non_blocking, _guard) = non_blocking(file_appender);
(Some(non_blocking), Some(_guard))
};
// Log to stdout (if you run with `RUST_LOG=debug`).
if let Some(non_blocking_writer) = maybe_non_blocking {
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt};
let console_layer = fmt::layer().with_target(true).with_writer(std::io::stdout);
// Create the file layer (writes to the file)
let file_layer = fmt::layer()
.with_ansi(false)
.with_writer(non_blocking_writer);
let env_filter =
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("notedeck=info"));
// Set up the subscriber to combine both layers
tracing_subscriber::registry()
.with(console_layer)
.with(file_layer)
.with(env_filter)
.init();
} else {
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env())
.init();
}
maybe_guard
}
// Desktop
#[cfg(not(target_arch = "wasm32"))]
#[tokio::main]
async fn main() {
#[cfg(feature = "memory")]
re_memory::accounting_allocator::set_tracking_callstacks(true);
let base_path = DataPath::default_base_or_cwd();
let path = DataPath::new(base_path.clone());
// This guard must be scoped for the duration of the entire program so all logs will be written
let _guard = setup_logging(&path);
let _res = eframe::run_native(
"Damus Notedeck",
generate_native_options(path),
Box::new(|cc| {
let args: Vec<String> = std::env::args().collect();
let ctx = &cc.egui_ctx;
let mut notedeck = Notedeck::new(ctx, base_path, &args);
notedeck.setup(ctx);
let chrome = Chrome::new_with_apps(cc, &args, &mut notedeck)?;
notedeck.set_app(chrome);
Ok(Box::new(notedeck))
}),
);
}
/*
* TODO: nostrdb not supported on web
*
#[cfg(target_arch = "wasm32")]
pub fn main() {
// Make sure panics are logged using `console.error`.
console_error_panic_hook::set_once();
// Redirect tracing to console.log and friends:
tracing_wasm::set_as_global_default();
wasm_bindgen_futures::spawn_local(async {
let web_options = eframe::WebOptions::default();
eframe::start_web(
"the_canvas_id", // hardcode it
web_options,
Box::new(|cc| Box::new(Damus::new(cc, "."))),
)
.await
.expect("failed to start eframe");
});
}
*/
#[cfg(test)]
mod tests {
use super::Notedeck;
use notedeck_columns::Damus;
use std::path::{Path, PathBuf};
fn create_tmp_dir() -> PathBuf {
tempfile::TempDir::new()
.expect("tmp path")
.path()
.to_path_buf()
}
fn rmrf(path: impl AsRef<Path>) {
let _ = std::fs::remove_dir_all(path);
}
/// Ensure dbpath actually sets the dbpath correctly.
#[tokio::test]
async fn test_dbpath() {
let datapath = create_tmp_dir();
let dbpath = create_tmp_dir();
let args: Vec<String> = [
"--testrunner",
"--datapath",
&datapath.to_str().unwrap(),
"--dbpath",
&dbpath.to_str().unwrap(),
]
.iter()
.map(|s| s.to_string())
.collect();
let ctx = egui::Context::default();
let _app = Notedeck::new(&ctx, &datapath, &args);
assert!(Path::new(&dbpath.join("data.mdb")).exists());
assert!(Path::new(&dbpath.join("lock.mdb")).exists());
assert!(!Path::new(&datapath.join("db")).exists());
rmrf(datapath);
rmrf(dbpath);
}
#[tokio::test]
async fn test_column_args() {
let tmpdir = create_tmp_dir();
let npub = "npub1xtscya34g58tk0z605fvr788k263gsu6cy9x0mhnm87echrgufzsevkk5s";
let args: Vec<String> = [
"--testrunner",
"--no-keystore",
"--pub",
npub,
"-c",
"notifications",
"-c",
"contacts",
]
.iter()
.map(|s| s.to_string())
.collect();
let ctx = egui::Context::default();
let mut notedeck = Notedeck::new(&ctx, &tmpdir, &args);
let mut app_ctx = notedeck.app_context();
let app = Damus::new(&mut app_ctx, &args);
assert_eq!(app.columns(app_ctx.accounts).columns().len(), 2);
let tl1 = app
.columns(app_ctx.accounts)
.column(0)
.router()
.top()
.timeline_id()
.unwrap();
let tl2 = app
.columns(app_ctx.accounts)
.column(1)
.router()
.top()
.timeline_id()
.unwrap();
assert_eq!(app.timeline_cache.num_timelines(), 2);
assert!(app.timeline_cache.get(&tl1).is_some());
assert!(app.timeline_cache.get(&tl2).is_some());
rmrf(tmpdir);
}
#[tokio::test]
async fn test_unknown_args() {
let tmpdir = create_tmp_dir();
let npub = "npub1xtscya34g58tk0z605fvr788k263gsu6cy9x0mhnm87echrgufzsevkk5s";
let args: Vec<String> = [
"--testrunner",
"--no-keystore",
"--unknown-arg", // <-- UNKNOWN
"--pub",
npub,
"-c",
"notifications",
"-c",
"contacts",
]
.iter()
.map(|s| s.to_string())
.collect();
let ctx = egui::Context::default();
let mut notedeck = Notedeck::new(&ctx, &tmpdir, &args);
let mut app_ctx = notedeck.app_context();
let app = Damus::new(&mut app_ctx, &args);
// ensure we recognized all the arguments
let completely_unrecognized: Vec<String> = notedeck
.unrecognized_args()
.intersection(app.unrecognized_args())
.cloned()
.collect();
assert_eq!(completely_unrecognized, ["--unknown-arg"]);
rmrf(tmpdir);
}
}