Add option to export plain text room logs
This commit is contained in:
parent
02d3b067b8
commit
0ccf788d7b
5 changed files with 258 additions and 14 deletions
136
Cargo.lock
generated
136
Cargo.lock
generated
|
|
@ -48,6 +48,17 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
|
|
@ -119,6 +130,45 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
"clap_lex",
|
||||
"indexmap",
|
||||
"once_cell",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"textwrap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.3"
|
||||
|
|
@ -142,6 +192,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"async-trait",
|
||||
"chrono",
|
||||
"clap",
|
||||
"crossterm",
|
||||
"directories",
|
||||
"edit",
|
||||
|
|
@ -157,6 +208,7 @@ dependencies = [
|
|||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"toss",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -414,15 +466,27 @@ dependencies = [
|
|||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"hashbrown 0.11.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
|
|
@ -460,6 +524,16 @@ dependencies = [
|
|||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown 0.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
|
|
@ -590,6 +664,12 @@ version = "0.1.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
|
||||
|
||||
[[package]]
|
||||
name = "palette"
|
||||
version = "0.6.0"
|
||||
|
|
@ -666,6 +746,30 @@ version = "0.2.16"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.40"
|
||||
|
|
@ -979,6 +1083,12 @@ version = "0.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.98"
|
||||
|
|
@ -1004,6 +1114,21 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.31"
|
||||
|
|
@ -1346,6 +1471,15 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ edition = "2021"
|
|||
anyhow = "1.0.58"
|
||||
async-trait = "0.1.56"
|
||||
chrono = { version = "0.4.19", features = ["serde"] }
|
||||
clap = { version = "3.2.8", features = ["derive"] }
|
||||
crossterm = "0.24.0"
|
||||
directories = "4.0.1"
|
||||
edit = "0.1.4"
|
||||
|
|
@ -20,6 +21,7 @@ serde = { version = "1.0.138", features = ["derive"] }
|
|||
serde_json = "1.0.82"
|
||||
thiserror = "1.0.31"
|
||||
tokio = { version = "1.19.2", features = ["full"] }
|
||||
unicode-width = "0.1.9"
|
||||
|
||||
[dependencies.tokio-tungstenite]
|
||||
version = "0.17.1"
|
||||
|
|
|
|||
72
src/export.rs
Normal file
72
src/export.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
//! Export logs from the vault to plain text files.
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::path::Path;
|
||||
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use crate::euph::api::Snowflake;
|
||||
use crate::store::{MsgStore, Tree};
|
||||
use crate::vault::{EuphMsg, Vault};
|
||||
|
||||
const TIME_FORMAT: &str = "%F %T";
|
||||
const TIME_EMPTY: &str = " ";
|
||||
|
||||
pub async fn export(vault: &Vault, room: String, file: &Path) -> anyhow::Result<()> {
|
||||
let mut file = BufWriter::new(File::create(file)?);
|
||||
let vault = vault.euph(room);
|
||||
|
||||
let mut tree_id = vault.first_tree().await;
|
||||
while let Some(some_tree_id) = tree_id {
|
||||
let tree = vault.tree(&some_tree_id).await;
|
||||
write_tree(&mut file, &tree, some_tree_id, 0)?;
|
||||
tree_id = vault.next_tree(&some_tree_id).await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_tree(
|
||||
file: &mut BufWriter<File>,
|
||||
tree: &Tree<EuphMsg>,
|
||||
id: Snowflake,
|
||||
indent: usize,
|
||||
) -> anyhow::Result<()> {
|
||||
let indent_string = "| ".repeat(indent);
|
||||
|
||||
if let Some(msg) = tree.msg(&id) {
|
||||
write_msg(file, &indent_string, msg)?;
|
||||
} else {
|
||||
write_placeholder(file, &indent_string)?;
|
||||
}
|
||||
|
||||
if let Some(children) = tree.children(&id) {
|
||||
for child in children {
|
||||
write_tree(file, tree, *child, indent + 1)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_msg(file: &mut BufWriter<File>, indent_string: &str, msg: &EuphMsg) -> anyhow::Result<()> {
|
||||
let nick = &msg.nick;
|
||||
let nick_empty = " ".repeat(nick.width());
|
||||
|
||||
for (i, line) in msg.content.lines().enumerate() {
|
||||
if i == 0 {
|
||||
let time = msg.time.0.format(TIME_FORMAT);
|
||||
writeln!(file, "{time} {indent_string}[{nick}] {line}")?;
|
||||
} else {
|
||||
writeln!(file, "{TIME_EMPTY} {indent_string} {nick_empty} {line}")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_placeholder(file: &mut BufWriter<File>, indent_string: &str) -> anyhow::Result<()> {
|
||||
writeln!(file, "{TIME_EMPTY} {indent_string}...")?;
|
||||
Ok(())
|
||||
}
|
||||
52
src/main.rs
52
src/main.rs
|
|
@ -3,21 +3,65 @@
|
|||
// TODO Clean up use and manipulation of toss Pos and Size
|
||||
|
||||
mod euph;
|
||||
mod export;
|
||||
mod logger;
|
||||
mod replies;
|
||||
mod store;
|
||||
mod ui;
|
||||
mod vault;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::Parser;
|
||||
use directories::ProjectDirs;
|
||||
use log::info;
|
||||
use toss::terminal::Terminal;
|
||||
use ui::Ui;
|
||||
use vault::Vault;
|
||||
|
||||
use crate::logger::Logger;
|
||||
|
||||
#[derive(Debug, clap::Subcommand)]
|
||||
enum Command {
|
||||
/// Run the client interactively (default).
|
||||
Run,
|
||||
/// Export logs for a single room as a plain text file.
|
||||
Export { room: String, file: PathBuf },
|
||||
}
|
||||
|
||||
impl Default for Command {
|
||||
fn default() -> Self {
|
||||
Self::Run
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, clap::Parser)]
|
||||
struct Args {
|
||||
#[clap(subcommand)]
|
||||
command: Option<Command>,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let args = Args::parse();
|
||||
|
||||
let dirs = ProjectDirs::from("de", "plugh", "cove").expect("unable to determine directories");
|
||||
println!("Data dir: {}", dirs.data_dir().to_string_lossy());
|
||||
|
||||
let vault = vault::launch(&dirs.data_dir().join("vault.db"))?;
|
||||
|
||||
match args.command.unwrap_or_default() {
|
||||
Command::Run => run(&vault).await?,
|
||||
Command::Export { room, file } => export::export(&vault, room, &file).await?,
|
||||
}
|
||||
|
||||
vault.close().await;
|
||||
|
||||
println!("Goodbye!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn run(vault: &Vault) -> anyhow::Result<()> {
|
||||
let (logger, logger_rx) = Logger::init(log::Level::Debug);
|
||||
info!(
|
||||
"Welcome to {} {}",
|
||||
|
|
@ -25,18 +69,10 @@ async fn main() -> anyhow::Result<()> {
|
|||
env!("CARGO_PKG_VERSION")
|
||||
);
|
||||
|
||||
let dirs = ProjectDirs::from("de", "plugh", "cove").expect("unable to determine directories");
|
||||
println!("Data dir: {}", dirs.data_dir().to_string_lossy());
|
||||
|
||||
let vault = vault::launch(&dirs.data_dir().join("vault.db"))?;
|
||||
|
||||
let mut terminal = Terminal::new()?;
|
||||
// terminal.set_measuring(true);
|
||||
Ui::run(&mut terminal, vault.clone(), logger, logger_rx).await?;
|
||||
drop(terminal); // So the vault can print again
|
||||
|
||||
vault.close().await;
|
||||
|
||||
println!("Goodbye!");
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,11 +41,11 @@ impl FromSql for Time {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EuphMsg {
|
||||
id: Snowflake,
|
||||
parent: Option<Snowflake>,
|
||||
time: Time,
|
||||
nick: String,
|
||||
content: String,
|
||||
pub id: Snowflake,
|
||||
pub parent: Option<Snowflake>,
|
||||
pub time: Time,
|
||||
pub nick: String,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
impl Msg for EuphMsg {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue