online Minecraft written book viewer
1use std::time::{Instant, SystemTime};
2
3use anyhow::Context;
4use clap::Parser as _;
5use nara_core::BookContainer;
6use nara_slurper_1_12_infinity::Realm;
7
8use crate::{
9 cli::{Cli, Command, ServeArgs},
10 library::Library,
11 web::start_webserver,
12};
13use nara_slurper_1_12_world::slurp_world;
14
15pub mod cli;
16pub mod library;
17pub mod web;
18
19pub const VERSION: &str = env!("CARGO_PKG_VERSION");
20
21#[tokio::main]
22async fn main() -> anyhow::Result<()> {
23 tracing_subscriber::fmt::init();
24 let cli = Cli::parse();
25
26 match cli.command {
27 Command::Serve(args) => {
28 let library = build_library(&args).context("Building library")?;
29
30 if args.start_webserver {
31 start_webserver(&args, library)
32 .await
33 .context("Running webserver")?;
34 }
35 }
36 Command::SlurpWorld(args) => match args.version {
37 cli::MinecraftVersion::V1_12 => {
38 let num_workers = args.workers.unwrap_or_else(|| {
39 std::thread::available_parallelism()
40 .map(|n| n.get())
41 .unwrap_or(4)
42 });
43 let mut container =
44 BookContainer::open_or_new(&args.container_path)
45 .context("Opening container")?;
46 let start = Instant::now();
47 let books = slurp_world(&args.world_path, num_workers)
48 .await
49 .context("Slurping world")?;
50 let elapsed_ms = start.elapsed().as_secs_f64() * 1000.0;
51 let total = books.len();
52 let dupes = books
53 .into_iter()
54 .filter(|b| !container.add(b.clone()))
55 .count();
56 container
57 .save(&args.container_path)
58 .context("Saving container")?;
59 tracing::info!(
60 "Found {total} books, of which {dupes} were duplicates in {elapsed_ms:.3} ms"
61 );
62 }
63 },
64 Command::SlurpRealm(args) => match args.version {
65 cli::MinecraftVersion::V1_12 => {
66 let mut container =
67 BookContainer::open_or_new(&args.container_path)
68 .context("Opening container")?;
69 let start = Instant::now();
70 let books = Realm::read(args.realm_path)?.slurp();
71 let elapsed_ms = start.elapsed().as_secs_f64() * 1000.0;
72 let total = books.len();
73 let dupes = books
74 .into_iter()
75 .filter(|b| !container.add(b.clone()))
76 .count();
77 container
78 .save(&args.container_path)
79 .context("Saving container")?;
80 tracing::info!(
81 "Found {total} books, of which {dupes} were duplicates in {elapsed_ms:.3} ms"
82 );
83 }
84 },
85 }
86
87 Ok(())
88}
89
90fn build_library(args: &ServeArgs) -> anyhow::Result<Library> {
91 let start = SystemTime::now();
92 tracing::info!("Opening book container...");
93 let container = BookContainer::open_or_new(&args.container_path)
94 .context("Opening container")?;
95 tracing::info!(
96 "Container opened, took {} ms. Building library...",
97 SystemTime::now().duration_since(start)?.as_nanos() / 1_000_000
98 );
99
100 let start = SystemTime::now();
101 let mut library = Library::new(
102 args.content_threshold,
103 args.title_threshold,
104 args.author_threshold,
105 );
106 for book in container.books() {
107 library.add_book(
108 book.clone(),
109 args.warn_empty,
110 args.filter_empty_books,
111 );
112 }
113 tracing::info!(
114 "Built library in {}ms",
115 SystemTime::now().duration_since(start)?.as_nanos() / 1_000_000
116 );
117 Ok(library)
118}