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",
|
"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]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
@ -119,6 +130,45 @@ dependencies = [
|
||||||
"winapi",
|
"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]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
|
|
@ -142,6 +192,7 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"clap",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"directories",
|
"directories",
|
||||||
"edit",
|
"edit",
|
||||||
|
|
@ -157,6 +208,7 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-tungstenite",
|
"tokio-tungstenite",
|
||||||
"toss",
|
"toss",
|
||||||
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -414,15 +466,27 @@ dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashlink"
|
name = "hashlink"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf"
|
checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
|
|
@ -460,6 +524,16 @@ dependencies = [
|
||||||
"unicode-normalization",
|
"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]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
|
|
@ -590,6 +664,12 @@ version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_str_bytes"
|
||||||
|
version = "6.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "palette"
|
name = "palette"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
|
|
@ -666,6 +746,30 @@ version = "0.2.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
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]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.40"
|
version = "1.0.40"
|
||||||
|
|
@ -979,6 +1083,12 @@ version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.98"
|
version = "1.0.98"
|
||||||
|
|
@ -1004,6 +1114,21 @@ dependencies = [
|
||||||
"winapi",
|
"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]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.31"
|
version = "1.0.31"
|
||||||
|
|
@ -1346,6 +1471,15 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
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]]
|
[[package]]
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ edition = "2021"
|
||||||
anyhow = "1.0.58"
|
anyhow = "1.0.58"
|
||||||
async-trait = "0.1.56"
|
async-trait = "0.1.56"
|
||||||
chrono = { version = "0.4.19", features = ["serde"] }
|
chrono = { version = "0.4.19", features = ["serde"] }
|
||||||
|
clap = { version = "3.2.8", features = ["derive"] }
|
||||||
crossterm = "0.24.0"
|
crossterm = "0.24.0"
|
||||||
directories = "4.0.1"
|
directories = "4.0.1"
|
||||||
edit = "0.1.4"
|
edit = "0.1.4"
|
||||||
|
|
@ -20,6 +21,7 @@ serde = { version = "1.0.138", features = ["derive"] }
|
||||||
serde_json = "1.0.82"
|
serde_json = "1.0.82"
|
||||||
thiserror = "1.0.31"
|
thiserror = "1.0.31"
|
||||||
tokio = { version = "1.19.2", features = ["full"] }
|
tokio = { version = "1.19.2", features = ["full"] }
|
||||||
|
unicode-width = "0.1.9"
|
||||||
|
|
||||||
[dependencies.tokio-tungstenite]
|
[dependencies.tokio-tungstenite]
|
||||||
version = "0.17.1"
|
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
|
// TODO Clean up use and manipulation of toss Pos and Size
|
||||||
|
|
||||||
mod euph;
|
mod euph;
|
||||||
|
mod export;
|
||||||
mod logger;
|
mod logger;
|
||||||
mod replies;
|
mod replies;
|
||||||
mod store;
|
mod store;
|
||||||
mod ui;
|
mod ui;
|
||||||
mod vault;
|
mod vault;
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
use directories::ProjectDirs;
|
use directories::ProjectDirs;
|
||||||
use log::info;
|
use log::info;
|
||||||
use toss::terminal::Terminal;
|
use toss::terminal::Terminal;
|
||||||
use ui::Ui;
|
use ui::Ui;
|
||||||
|
use vault::Vault;
|
||||||
|
|
||||||
use crate::logger::Logger;
|
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]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
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);
|
let (logger, logger_rx) = Logger::init(log::Level::Debug);
|
||||||
info!(
|
info!(
|
||||||
"Welcome to {} {}",
|
"Welcome to {} {}",
|
||||||
|
|
@ -25,18 +69,10 @@ async fn main() -> anyhow::Result<()> {
|
||||||
env!("CARGO_PKG_VERSION")
|
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()?;
|
let mut terminal = Terminal::new()?;
|
||||||
// terminal.set_measuring(true);
|
// terminal.set_measuring(true);
|
||||||
Ui::run(&mut terminal, vault.clone(), logger, logger_rx).await?;
|
Ui::run(&mut terminal, vault.clone(), logger, logger_rx).await?;
|
||||||
drop(terminal); // So the vault can print again
|
drop(terminal); // So the vault can print again
|
||||||
|
|
||||||
vault.close().await;
|
|
||||||
|
|
||||||
println!("Goodbye!");
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,11 +41,11 @@ impl FromSql for Time {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct EuphMsg {
|
pub struct EuphMsg {
|
||||||
id: Snowflake,
|
pub id: Snowflake,
|
||||||
parent: Option<Snowflake>,
|
pub parent: Option<Snowflake>,
|
||||||
time: Time,
|
pub time: Time,
|
||||||
nick: String,
|
pub nick: String,
|
||||||
content: String,
|
pub content: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Msg for EuphMsg {
|
impl Msg for EuphMsg {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue