refactor: Remove synchronization for context parameter

The context is only written to during initial setup. After that
it is only ever read, so no synchronization is necessary.
This commit is contained in:
Lucas Schwiderski 2023-01-04 09:27:52 +01:00
parent 96b29a3d2b
commit fddf8fcbbd
Signed by: lucas
GPG key ID: AA12679AAA6DF4D8
16 changed files with 83 additions and 146 deletions

View file

@ -1,9 +1,7 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc;
use clap::{value_parser, Arg, ArgMatches, Command}; use clap::{value_parser, Arg, ArgMatches, Command};
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use tokio::sync::RwLock;
pub(crate) fn _command_definition() -> Command { pub(crate) fn _command_definition() -> Command {
Command::new("build").about("Build a project").arg( Command::new("build").about("Build a project").arg(
@ -19,6 +17,6 @@ pub(crate) fn _command_definition() -> Command {
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub(crate) async fn run(_ctx: Arc<RwLock<sdk::Context>>, _matches: &ArgMatches) -> Result<()> { pub(crate) async fn run(_ctx: sdk::Context, _matches: &ArgMatches) -> Result<()> {
unimplemented!() unimplemented!()
} }

View file

@ -1,5 +1,4 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Arc;
use clap::{value_parser, Arg, ArgMatches, Command}; use clap::{value_parser, Arg, ArgMatches, Command};
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
@ -7,7 +6,6 @@ use color_eyre::eyre::Result;
use sdk::decompress; use sdk::decompress;
use tokio::fs::{self, File}; use tokio::fs::{self, File};
use tokio::io::BufReader; use tokio::io::BufReader;
use tokio::sync::RwLock;
pub(crate) fn command_definition() -> Command { pub(crate) fn command_definition() -> Command {
Command::new("decompress") Command::new("decompress")
@ -37,11 +35,7 @@ pub(crate) fn command_definition() -> Command {
} }
#[tracing::instrument(skip(ctx))] #[tracing::instrument(skip(ctx))]
async fn decompress_bundle<P1, P2>( async fn decompress_bundle<P1, P2>(ctx: &sdk::Context, bundle: P1, destination: P2) -> Result<()>
ctx: Arc<RwLock<sdk::Context>>,
bundle: P1,
destination: P2,
) -> Result<()>
where where
P1: AsRef<Path> + std::fmt::Debug, P1: AsRef<Path> + std::fmt::Debug,
P2: AsRef<Path> + std::fmt::Debug, P2: AsRef<Path> + std::fmt::Debug,
@ -54,7 +48,7 @@ where
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) -> Result<()> { pub(crate) async fn run(ctx: sdk::Context, matches: &ArgMatches) -> Result<()> {
let bundle = matches let bundle = matches
.get_one::<PathBuf>("bundle") .get_one::<PathBuf>("bundle")
.expect("required argument 'bundle' is missing"); .expect("required argument 'bundle' is missing");
@ -70,8 +64,8 @@ pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) ->
let name = bundle.file_name(); let name = bundle.file_name();
if is_dir && name.is_some() { if is_dir && name.is_some() {
decompress_bundle(ctx, bundle, out_path.join(name.unwrap())).await decompress_bundle(&ctx, bundle, out_path.join(name.unwrap())).await
} else { } else {
decompress_bundle(ctx, bundle, out_path).await decompress_bundle(&ctx, bundle, out_path).await
} }
} }

View file

@ -1,5 +1,4 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Arc;
use clap::{value_parser, Arg, ArgAction, ArgMatches, Command}; use clap::{value_parser, Arg, ArgAction, ArgMatches, Command};
use color_eyre::eyre::{self, Context, Result}; use color_eyre::eyre::{self, Context, Result};
@ -8,7 +7,7 @@ use futures::future::try_join_all;
use futures::{StreamExt, TryFutureExt}; use futures::{StreamExt, TryFutureExt};
use glob::Pattern; use glob::Pattern;
use sdk::{Bundle, BundleFile}; use sdk::{Bundle, BundleFile};
use tokio::{fs, sync::RwLock}; use tokio::fs;
use crate::cmd::util::resolve_bundle_paths; use crate::cmd::util::resolve_bundle_paths;
@ -116,7 +115,7 @@ pub(crate) fn command_definition() -> Command {
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) -> Result<()> { pub(crate) async fn run(mut ctx: sdk::Context, matches: &ArgMatches) -> Result<()> {
{ {
let ljd_bin = matches let ljd_bin = matches
.get_one::<String>("ljd") .get_one::<String>("ljd")
@ -128,7 +127,6 @@ pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) ->
.get_one::<String>("ww2ogg") .get_one::<String>("ww2ogg")
.expect("no default value for 'ww2ogg' parameter"); .expect("no default value for 'ww2ogg' parameter");
let mut ctx = ctx.write().await;
ctx.ljd = Some(ljd_bin.clone()); ctx.ljd = Some(ljd_bin.clone());
ctx.revorb = Some(revorb_bin.clone()); ctx.revorb = Some(revorb_bin.clone());
ctx.ww2ogg = Some(ww2ogg_bin.clone()); ctx.ww2ogg = Some(ww2ogg_bin.clone());
@ -181,10 +179,10 @@ pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) ->
// TODO: Find a way to do this with `for_each_concurrent`. The first attempt // TODO: Find a way to do this with `for_each_concurrent`. The first attempt
// just kept head-butting into a "use of moved value" wall. // just kept head-butting into a "use of moved value" wall.
while let Some(path) = paths.next().await { while let Some(path) = paths.next().await {
let res = Bundle::open(ctx.clone(), &path) let res = Bundle::open(&ctx, &path)
.and_then(|bundle| { .and_then(|bundle| {
extract_bundle( extract_bundle(
ctx.clone(), &ctx,
bundle, bundle,
&dest, &dest,
ExtractOptions { ExtractOptions {
@ -220,7 +218,7 @@ struct ExtractOptions<'a> {
fields(decompile = options.decompile, flatten = options.flatten, dry_run = options.dry_run) fields(decompile = options.decompile, flatten = options.flatten, dry_run = options.dry_run)
)] )]
async fn extract_bundle<P>( async fn extract_bundle<P>(
ctx: Arc<RwLock<sdk::Context>>, ctx: &sdk::Context,
bundle: Bundle, bundle: Bundle,
dest: P, dest: P,
options: ExtractOptions<'_>, options: ExtractOptions<'_>,
@ -277,7 +275,7 @@ where
for file in files { for file in files {
let name = file.name(options.decompile, None); let name = file.name(options.decompile, None);
let data = if options.decompile { let data = if options.decompile {
file.decompiled(ctx.clone()).await file.decompiled(ctx).await
} else { } else {
file.raw() file.raw()
}; };

View file

@ -1,12 +1,11 @@
use std::{path::PathBuf, sync::Arc}; use std::path::PathBuf;
use clap::{value_parser, Arg, ArgMatches, Command}; use clap::{value_parser, Arg, ArgMatches, Command};
use color_eyre::{ use color_eyre::eyre::{self, Context, Result};
eyre::{self, Context, Result}, use color_eyre::Help;
Help,
};
use sdk::Bundle; use sdk::Bundle;
use tokio::{fs::File, io::AsyncReadExt, sync::RwLock}; use tokio::fs::File;
use tokio::io::AsyncReadExt;
pub(crate) fn command_definition() -> Command { pub(crate) fn command_definition() -> Command {
Command::new("inject") Command::new("inject")
@ -42,7 +41,7 @@ pub(crate) fn command_definition() -> Command {
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) -> Result<()> { pub(crate) async fn run(ctx: sdk::Context, matches: &ArgMatches) -> Result<()> {
let bundle_path = matches let bundle_path = matches
.get_one::<PathBuf>("bundle") .get_one::<PathBuf>("bundle")
.expect("required parameter not found"); .expect("required parameter not found");
@ -53,7 +52,7 @@ pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) ->
tracing::trace!(bundle_path = %bundle_path.display(), file_path = %file_path.display()); tracing::trace!(bundle_path = %bundle_path.display(), file_path = %file_path.display());
let mut bundle = Bundle::open(ctx.clone(), bundle_path) let mut bundle = Bundle::open(&ctx, bundle_path)
.await .await
.wrap_err("Failed to open bundle file")?; .wrap_err("Failed to open bundle file")?;
@ -66,8 +65,7 @@ pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) ->
.files_mut() .files_mut()
.filter(|file| file.matches_name(_name)) .filter(|file| file.matches_name(_name))
// TODO: Handle file variants // TODO: Handle file variants
.filter_map(|file| file.variants_mut().next()) .find_map(|file| file.variants_mut().next())
.next()
{ {
let mut data = Vec::new(); let mut data = Vec::new();
file.read_to_end(&mut data) file.read_to_end(&mut data)
@ -101,7 +99,7 @@ pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) ->
.await .await
.wrap_err_with(|| format!("failed to open output file {}", out_path.display()))?; .wrap_err_with(|| format!("failed to open output file {}", out_path.display()))?;
bundle bundle
.write(ctx.clone(), &mut out_file) .write(&ctx, &mut out_file)
.await .await
.wrap_err("failed to write changed bundle to output")?; .wrap_err("failed to write changed bundle to output")?;

View file

@ -6,7 +6,6 @@ use color_eyre::eyre::{self, Result};
use color_eyre::{Help, SectionExt}; use color_eyre::{Help, SectionExt};
use futures::StreamExt; use futures::StreamExt;
use sdk::Bundle; use sdk::Bundle;
use tokio::sync::RwLock;
use tracing::Instrument; use tracing::Instrument;
use crate::cmd::util::resolve_bundle_paths; use crate::cmd::util::resolve_bundle_paths;
@ -64,7 +63,7 @@ fn print_bundle_list(bundle: Bundle, fmt: OutputFormat) {
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) -> Result<()> { pub(crate) async fn run(ctx: sdk::Context, matches: &ArgMatches) -> Result<()> {
let bundles = matches let bundles = matches
.get_many::<PathBuf>("bundle") .get_many::<PathBuf>("bundle")
.unwrap_or_default() .unwrap_or_default()
@ -78,13 +77,15 @@ pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) ->
OutputFormat::Text OutputFormat::Text
}; };
let ctx = Arc::new(ctx);
paths paths
.for_each_concurrent(10, |p| async { .for_each_concurrent(10, |p| async {
let span = tracing::info_span!("list bundle"); let span = tracing::info_span!("list bundle");
let ctx = ctx.clone(); let ctx = ctx.clone();
async move { async move {
let span = tracing::info_span!("open bundle"); let span = tracing::info_span!("open bundle");
if let Err(err) = Bundle::open(ctx, &p) if let Err(err) = Bundle::open(&ctx, &p)
.instrument(span) .instrument(span)
.await .await
.map(|bundle| print_bundle_list(bundle, fmt)) .map(|bundle| print_bundle_list(bundle, fmt))

View file

@ -1,9 +1,5 @@
use std::sync::Arc;
use clap::{Arg, ArgMatches, Command}; use clap::{Arg, ArgMatches, Command};
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use tokio::sync::RwLock;
use sdk::Oodle; use sdk::Oodle;
mod decompress; mod decompress;
@ -39,10 +35,9 @@ pub(crate) fn command_definition() -> Command {
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) -> Result<()> { pub(crate) async fn run(mut ctx: sdk::Context, matches: &ArgMatches) -> Result<()> {
if let Some(name) = matches.get_one::<String>("oodle") { if let Some(name) = matches.get_one::<String>("oodle") {
let oodle = Oodle::new(name)?; let oodle = Oodle::new(name)?;
let mut ctx = ctx.write().await;
ctx.oodle = Some(oodle); ctx.oodle = Some(oodle);
} }

View file

@ -1,12 +1,10 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc;
use clap::{value_parser, Arg, ArgAction, ArgMatches, Command, ValueEnum}; use clap::{value_parser, Arg, ArgAction, ArgMatches, Command, ValueEnum};
use color_eyre::eyre::{Context, Result}; use color_eyre::eyre::{Context, Result};
use color_eyre::{Help, SectionExt}; use color_eyre::{Help, SectionExt};
use tokio::fs::File; use tokio::fs::File;
use tokio::io::{AsyncBufReadExt, BufReader}; use tokio::io::{AsyncBufReadExt, BufReader};
use tokio::sync::RwLock;
use tokio_stream::wrappers::LinesStream; use tokio_stream::wrappers::LinesStream;
use tokio_stream::StreamExt; use tokio_stream::StreamExt;
@ -77,7 +75,7 @@ pub(crate) fn command_definition() -> Command {
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) -> Result<()> { pub(crate) async fn run(mut ctx: sdk::Context, matches: &ArgMatches) -> Result<()> {
match matches.subcommand() { match matches.subcommand() {
Some(("lookup", sub_matches)) => { Some(("lookup", sub_matches)) => {
let hash = sub_matches let hash = sub_matches
@ -88,7 +86,6 @@ pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) ->
.get_many::<HashGroup>("group") .get_many::<HashGroup>("group")
.unwrap_or_default(); .unwrap_or_default();
let ctx = ctx.read().await;
for group in groups { for group in groups {
let value = ctx.lookup_hash(*hash, (*group).into()); let value = ctx.lookup_hash(*hash, (*group).into());
println!("{value}"); println!("{value}");
@ -112,18 +109,19 @@ pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) ->
BufReader::new(Box::new(f)) BufReader::new(Box::new(f))
}; };
let group = sdk::murmur::HashGroup::from(*group);
let mut added = 0; let mut added = 0;
let mut skipped = 0; let mut skipped = 0;
let lines: Vec<_> = LinesStream::new(r.lines()).collect().await; let lines: Vec<_> = LinesStream::new(r.lines()).collect().await;
let total = { let total = {
let mut ctx = ctx.write().await;
for line in lines.into_iter() { for line in lines.into_iter() {
let value = line?; let value = line?;
if ctx.lookup.find(&value, (*group).into()).is_some() { if ctx.lookup.find(&value, group).is_some() {
skipped += 1; skipped += 1;
} else { } else {
ctx.lookup.add(value, (*group).into()); ctx.lookup.add(value, group);
added += 1; added += 1;
} }
} }
@ -145,9 +143,7 @@ pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) ->
}) })
.with_section(|| out_path.display().to_string().header("Path:"))?; .with_section(|| out_path.display().to_string().header("Path:"))?;
ctx.read() ctx.lookup
.await
.lookup
.to_csv(f) .to_csv(f)
.await .await
.wrap_err("Failed to write dictionary to disk")?; .wrap_err("Failed to write dictionary to disk")?;
@ -175,9 +171,7 @@ pub(crate) async fn run(ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) ->
}) })
.with_section(|| out_path.display().to_string().header("Path:"))?; .with_section(|| out_path.display().to_string().header("Path:"))?;
ctx.read() ctx.lookup
.await
.lookup
.to_csv(f) .to_csv(f)
.await .await
.wrap_err("Failed to write dictionary to disk") .wrap_err("Failed to write dictionary to disk")

View file

@ -1,9 +1,6 @@
use std::sync::Arc;
use clap::{Arg, ArgAction, ArgMatches, Command}; use clap::{Arg, ArgAction, ArgMatches, Command};
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use sdk::murmur::{Murmur32, Murmur64}; use sdk::murmur::{Murmur32, Murmur64};
use tokio::sync::RwLock;
pub(crate) fn command_definition() -> Command { pub(crate) fn command_definition() -> Command {
Command::new("murmur") Command::new("murmur")
@ -28,7 +25,7 @@ pub(crate) fn command_definition() -> Command {
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub(crate) async fn run(_ctx: Arc<RwLock<sdk::Context>>, matches: &ArgMatches) -> Result<()> { pub(crate) async fn run(_ctx: sdk::Context, matches: &ArgMatches) -> Result<()> {
match matches.subcommand() { match matches.subcommand() {
Some(("hash", sub_matches)) => { Some(("hash", sub_matches)) => {
let s = sub_matches let s = sub_matches

View file

@ -1,8 +1,5 @@
use std::sync::Arc;
use clap::{Arg, ArgMatches, Command}; use clap::{Arg, ArgMatches, Command};
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use tokio::sync::RwLock;
pub(crate) fn _command_definition() -> Command { pub(crate) fn _command_definition() -> Command {
Command::new("new") Command::new("new")
@ -17,6 +14,6 @@ pub(crate) fn _command_definition() -> Command {
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub(crate) async fn run(_ctx: Arc<RwLock<sdk::Context>>, _matches: &ArgMatches) -> Result<()> { pub(crate) async fn run(_ctx: sdk::Context, _matches: &ArgMatches) -> Result<()> {
unimplemented!() unimplemented!()
} }

View file

@ -1,9 +1,7 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc;
use clap::{value_parser, Arg, ArgMatches, Command}; use clap::{value_parser, Arg, ArgMatches, Command};
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use tokio::sync::RwLock;
pub(crate) fn _command_definition() -> Command { pub(crate) fn _command_definition() -> Command {
Command::new("watch") Command::new("watch")
@ -21,6 +19,6 @@ pub(crate) fn _command_definition() -> Command {
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub(crate) async fn run(_ctx: Arc<RwLock<sdk::Context>>, _matches: &ArgMatches) -> Result<()> { pub(crate) async fn run(_ctx: sdk::Context, _matches: &ArgMatches) -> Result<()> {
unimplemented!() unimplemented!()
} }

View file

@ -7,6 +7,7 @@ use std::sync::Arc;
use clap::parser::ValueSource; use clap::parser::ValueSource;
use clap::value_parser; use clap::value_parser;
use clap::{command, Arg}; use clap::{command, Arg};
use color_eyre::eyre;
use color_eyre::eyre::{Context, Result}; use color_eyre::eyre::{Context, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::fs::File; use tokio::fs::File;
@ -71,6 +72,7 @@ async fn main() -> Result<()> {
.init(); .init();
} }
// TODO: Move this into a `Context::init` method?
let ctx = sdk::Context::new(); let ctx = sdk::Context::new();
let ctx = Arc::new(RwLock::new(ctx)); let ctx = Arc::new(RwLock::new(ctx));
@ -83,7 +85,6 @@ async fn main() -> Result<()> {
let ctx = ctx.clone(); let ctx = ctx.clone();
tokio::spawn(async move { tokio::spawn(async move {
let mut ctx = ctx.write().await;
let res = File::open(&path) let res = File::open(&path)
.await .await
.wrap_err_with(|| format!("failed to open dictionary file: {}", path.display())); .wrap_err_with(|| format!("failed to open dictionary file: {}", path.display()));
@ -101,6 +102,7 @@ async fn main() -> Result<()> {
}; };
let r = BufReader::new(f); let r = BufReader::new(f);
let mut ctx = ctx.write().await;
if let Err(err) = ctx.lookup.from_csv(r).await { if let Err(err) = ctx.lookup.from_csv(r).await {
tracing::error!("{:#}", err); tracing::error!("{:#}", err);
} }
@ -129,6 +131,11 @@ async fn main() -> Result<()> {
tokio::try_join!(dicitonary_task, global_config_task)?; tokio::try_join!(dicitonary_task, global_config_task)?;
let ctx = match Arc::try_unwrap(ctx).map(|ctx| ctx.into_inner()) {
Ok(ctx) => ctx,
Err(_) => eyre::bail!("failed to unwrap context"),
};
match matches.subcommand() { match matches.subcommand() {
Some(("bundle", sub_matches)) => cmd::bundle::run(ctx, sub_matches).await?, Some(("bundle", sub_matches)) => cmd::bundle::run(ctx, sub_matches).await?,
Some(("murmur", sub_matches)) => cmd::murmur::run(ctx, sub_matches).await?, Some(("murmur", sub_matches)) => cmd::murmur::run(ctx, sub_matches).await?,

View file

@ -1,14 +1,11 @@
use std::io::Cursor; use std::io::Cursor;
use std::sync::Arc;
use color_eyre::{Help, Result, SectionExt}; use color_eyre::{Help, Result, SectionExt};
use futures::future::join_all; use futures::future::join_all;
use serde::Serialize; use serde::Serialize;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncSeek, AsyncWrite, AsyncWriteExt}; use tokio::io::{AsyncRead, AsyncReadExt, AsyncSeek, AsyncWrite, AsyncWriteExt};
use tokio::sync::RwLock;
use crate::binary::*; use crate::binary::*;
use crate::context::lookup_hash;
use crate::filetype::*; use crate::filetype::*;
use crate::murmur::{HashGroup, Murmur64}; use crate::murmur::{HashGroup, Murmur64};
@ -382,13 +379,13 @@ pub struct BundleFile {
impl BundleFile { impl BundleFile {
#[tracing::instrument(name = "File::read", skip_all)] #[tracing::instrument(name = "File::read", skip_all)]
pub async fn read<R>(ctx: Arc<RwLock<crate::Context>>, r: &mut R) -> Result<Self> pub async fn read<R>(ctx: &crate::Context, r: &mut R) -> Result<Self>
where where
R: AsyncRead + AsyncSeek + std::marker::Unpin, R: AsyncRead + AsyncSeek + std::marker::Unpin,
{ {
let file_type = BundleFileType::from(read_u64(r).await?); let file_type = BundleFileType::from(read_u64(r).await?);
let hash = Murmur64::from(read_u64(r).await?); let hash = Murmur64::from(read_u64(r).await?);
let name = lookup_hash(ctx, hash, HashGroup::Filename).await; let name = ctx.lookup_hash(hash, HashGroup::Filename);
let header_count = read_u32(r) let header_count = read_u32(r)
.await .await
@ -436,7 +433,7 @@ impl BundleFile {
} }
#[tracing::instrument(name = "File::write", skip_all)] #[tracing::instrument(name = "File::write", skip_all)]
pub async fn write<W>(&self, _ctx: Arc<RwLock<crate::Context>>, w: &mut W) -> Result<()> pub async fn write<W>(&self, w: &mut W) -> Result<()>
where where
W: AsyncWrite + AsyncSeek + std::marker::Unpin, W: AsyncWrite + AsyncSeek + std::marker::Unpin,
{ {
@ -536,7 +533,7 @@ impl BundleFile {
} }
#[tracing::instrument(name = "File::decompiled", skip_all)] #[tracing::instrument(name = "File::decompiled", skip_all)]
pub async fn decompiled(&self, ctx: Arc<RwLock<crate::Context>>) -> Result<Vec<UserFile>> { pub async fn decompiled(&self, ctx: &crate::Context) -> Result<Vec<UserFile>> {
let file_type = self.file_type(); let file_type = self.file_type();
if tracing::enabled!(tracing::Level::DEBUG) { if tracing::enabled!(tracing::Level::DEBUG) {
@ -548,42 +545,37 @@ impl BundleFile {
} }
if file_type == BundleFileType::Strings { if file_type == BundleFileType::Strings {
let ctx = ctx.read().await; return strings::decompile(ctx, &self.variants);
return strings::decompile(&ctx, &self.variants);
} }
let tasks = self.variants.iter().map(|variant| { let tasks = self.variants.iter().map(|variant| async move {
let ctx = ctx.clone(); let data = variant.data();
let name = if self.variants.len() > 1 {
self.name(true, Some(variant.header.variant))
} else {
self.name(true, None)
};
async move { let res = match file_type {
let data = variant.data(); BundleFileType::Lua => lua::decompile(ctx, data).await,
let name = if self.variants.len() > 1 { BundleFileType::Package => {
self.name(true, Some(variant.header.variant)) let mut c = Cursor::new(data);
} else { package::decompile(ctx, &mut c).await
self.name(true, None) }
}; _ => {
tracing::debug!("Can't decompile, unknown file type");
Ok(vec![UserFile::with_name(data.to_vec(), name.clone())])
}
};
let res = match file_type { match res {
BundleFileType::Lua => lua::decompile(ctx, data).await, Ok(files) => files,
BundleFileType::Package => { Err(err) => {
let mut c = Cursor::new(data); let err = err
package::decompile(ctx, &mut c).await .wrap_err("failed to decompile file")
} .with_section(|| name.header("File:"));
_ => { tracing::error!("{:?}", err);
tracing::debug!("Can't decompile, unknown file type"); vec![]
Ok(vec![UserFile::with_name(data.to_vec(), name.clone())])
}
};
match res {
Ok(files) => files,
Err(err) => {
let err = err
.wrap_err("failed to decompile file")
.with_section(|| name.header("File:"));
tracing::error!("{:?}", err);
vec![]
}
} }
} }
}); });

View file

@ -1,6 +1,5 @@
use std::io::{Cursor, SeekFrom}; use std::io::{Cursor, SeekFrom};
use std::path::Path; use std::path::Path;
use std::sync::Arc;
use color_eyre::eyre::{self, Context, Result}; use color_eyre::eyre::{self, Context, Result};
use color_eyre::{Help, Report, SectionExt}; use color_eyre::{Help, Report, SectionExt};
@ -8,7 +7,6 @@ use tokio::fs;
use tokio::io::{ use tokio::io::{
AsyncRead, AsyncReadExt, AsyncSeek, AsyncSeekExt, AsyncWrite, AsyncWriteExt, BufReader, AsyncRead, AsyncReadExt, AsyncSeek, AsyncSeekExt, AsyncWrite, AsyncWriteExt, BufReader,
}; };
use tokio::sync::RwLock;
use tracing::Instrument; use tracing::Instrument;
use crate::binary::*; use crate::binary::*;
@ -107,7 +105,7 @@ pub struct Bundle {
impl Bundle { impl Bundle {
#[tracing::instrument(name = "Bundle::open", skip(ctx))] #[tracing::instrument(name = "Bundle::open", skip(ctx))]
pub async fn open<P>(ctx: Arc<RwLock<crate::Context>>, path: P) -> Result<Self> pub async fn open<P>(ctx: &crate::Context, path: P) -> Result<Self>
where where
P: AsRef<Path> + std::fmt::Debug, P: AsRef<Path> + std::fmt::Debug,
{ {
@ -117,7 +115,7 @@ impl Bundle {
let path = path.as_ref(); let path = path.as_ref();
let bundle_name = if let Some(name) = path.file_name() { let bundle_name = if let Some(name) = path.file_name() {
match Murmur64::try_from(name.to_string_lossy().as_ref()) { match Murmur64::try_from(name.to_string_lossy().as_ref()) {
Ok(hash) => ctx.read().await.lookup_hash(hash, HashGroup::Filename), Ok(hash) => ctx.lookup_hash(hash, HashGroup::Filename),
Err(err) => { Err(err) => {
tracing::debug!("failed to turn bundle name into hash: {}", err); tracing::debug!("failed to turn bundle name into hash: {}", err);
name.to_string_lossy().to_string() name.to_string_lossy().to_string()
@ -202,7 +200,6 @@ impl Bundle {
decompressed.append(&mut compressed_buffer); decompressed.append(&mut compressed_buffer);
} else { } else {
// TODO: Optimize to not reallocate? // TODO: Optimize to not reallocate?
let ctx = ctx.read().await;
let oodle_lib = ctx.oodle.as_ref().unwrap(); let oodle_lib = ctx.oodle.as_ref().unwrap();
let mut raw_buffer = oodle_lib let mut raw_buffer = oodle_lib
.decompress( .decompress(
@ -240,9 +237,7 @@ impl Bundle {
let mut files = Vec::with_capacity(num_entries); let mut files = Vec::with_capacity(num_entries);
for i in 0..num_entries { for i in 0..num_entries {
let span = tracing::trace_span!("", file_index = i); let span = tracing::trace_span!("", file_index = i);
let file = BundleFile::read(ctx.clone(), &mut r) let file = BundleFile::read(ctx, &mut r).instrument(span).await?;
.instrument(span)
.await?;
files.push(file); files.push(file);
} }
@ -257,7 +252,7 @@ impl Bundle {
} }
#[tracing::instrument(name = "Bundle::write", skip_all)] #[tracing::instrument(name = "Bundle::write", skip_all)]
pub async fn write<W>(&self, ctx: Arc<RwLock<crate::Context>>, w: &mut W) -> Result<()> pub async fn write<W>(&self, ctx: &crate::Context, w: &mut W) -> Result<()>
where where
W: AsyncWrite + AsyncSeek + std::marker::Unpin, W: AsyncWrite + AsyncSeek + std::marker::Unpin,
{ {
@ -279,7 +274,7 @@ impl Bundle {
async { async {
for file in self.files.iter() { for file in self.files.iter() {
file.write(ctx.clone(), &mut c).await?; file.write(&mut c).await?;
} }
Ok::<(), Report>(()) Ok::<(), Report>(())
@ -309,7 +304,6 @@ impl Bundle {
let chunks = unpacked_data.chunks(CHUNK_SIZE); let chunks = unpacked_data.chunks(CHUNK_SIZE);
let ctx = ctx.read().await;
let oodle_lib = ctx.oodle.as_ref().unwrap(); let oodle_lib = ctx.oodle.as_ref().unwrap();
let mut chunk_sizes = Vec::with_capacity(num_chunks); let mut chunk_sizes = Vec::with_capacity(num_chunks);
@ -351,7 +345,7 @@ impl Bundle {
/// This is mainly useful for debugging purposes or /// This is mainly useful for debugging purposes or
/// to manullay inspect the raw data. /// to manullay inspect the raw data.
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub async fn decompress<R, W>(ctx: Arc<RwLock<crate::Context>>, mut r: R, mut w: W) -> Result<()> pub async fn decompress<R, W>(ctx: &crate::Context, mut r: R, mut w: W) -> Result<()>
where where
R: AsyncRead + AsyncSeek + std::marker::Unpin, R: AsyncRead + AsyncSeek + std::marker::Unpin,
W: AsyncWrite + std::marker::Unpin, W: AsyncWrite + std::marker::Unpin,
@ -417,7 +411,6 @@ where
let mut compressed_buffer = vec![0u8; chunk_size]; let mut compressed_buffer = vec![0u8; chunk_size];
r.read_exact(&mut compressed_buffer).await?; r.read_exact(&mut compressed_buffer).await?;
let ctx = ctx.read().await;
let oodle_lib = ctx.oodle.as_ref().unwrap(); let oodle_lib = ctx.oodle.as_ref().unwrap();
// TODO: Optimize to not reallocate? // TODO: Optimize to not reallocate?
let mut raw_buffer = oodle_lib.decompress( let mut raw_buffer = oodle_lib.decompress(

View file

@ -1,7 +1,4 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc;
use tokio::sync::RwLock;
use crate::murmur::{Dictionary, HashGroup, Murmur32, Murmur64}; use crate::murmur::{Dictionary, HashGroup, Murmur32, Murmur64};
use crate::oodle::Oodle; use crate::oodle::Oodle;
@ -61,17 +58,3 @@ impl Default for Context {
Self::new() Self::new()
} }
} }
pub async fn lookup_hash<M>(ctx: Arc<RwLock<Context>>, hash: M, group: HashGroup) -> String
where
M: Into<Murmur64>,
{
let hash = hash.into();
if let Some(s) = ctx.read().await.lookup.lookup(hash, group) {
tracing::debug!(%hash, string = s, "Murmur64 lookup successful");
s.to_owned()
} else {
tracing::debug!(%hash, "Murmur64 lookup failed");
format!("{hash:016X}")
}
}

View file

@ -1,16 +1,11 @@
use std::io::Cursor; use std::io::Cursor;
use std::sync::Arc;
use color_eyre::Result; use color_eyre::Result;
use tokio::sync::RwLock;
use crate::bundle::file::UserFile; use crate::bundle::file::UserFile;
#[tracing::instrument(skip_all,fields(buf_len = data.as_ref().len()))] #[tracing::instrument(skip_all,fields(buf_len = data.as_ref().len()))]
pub(crate) async fn decompile<T>( pub(crate) async fn decompile<T>(_ctx: &crate::Context, data: T) -> Result<Vec<UserFile>>
_ctx: Arc<RwLock<crate::Context>>,
data: T,
) -> Result<Vec<UserFile>>
where where
T: AsRef<[u8]>, T: AsRef<[u8]>,
{ {

View file

@ -1,16 +1,13 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use color_eyre::eyre::Context; use color_eyre::eyre::Context;
use color_eyre::Result; use color_eyre::Result;
use serde::Serialize; use serde::Serialize;
use tokio::io::{AsyncRead, AsyncSeek}; use tokio::io::{AsyncRead, AsyncSeek};
use tokio::sync::RwLock;
use crate::binary::*; use crate::binary::*;
use crate::bundle::file::{BundleFileType, UserFile}; use crate::bundle::file::{BundleFileType, UserFile};
use crate::context::lookup_hash;
use crate::murmur::{HashGroup, Murmur64}; use crate::murmur::{HashGroup, Murmur64};
#[derive(Serialize)] #[derive(Serialize)]
@ -37,7 +34,7 @@ impl Package {
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub async fn decompile<R>(ctx: Arc<RwLock<crate::Context>>, data: &mut R) -> Result<Vec<UserFile>> pub async fn decompile<R>(ctx: &crate::Context, data: &mut R) -> Result<Vec<UserFile>>
where where
R: AsyncRead + AsyncSeek + std::marker::Unpin, R: AsyncRead + AsyncSeek + std::marker::Unpin,
{ {
@ -53,7 +50,7 @@ where
for i in 0..file_count { for i in 0..file_count {
let t = BundleFileType::from(read_u64(data).await?); let t = BundleFileType::from(read_u64(data).await?);
let hash = Murmur64::from(read_u64(data).await?); let hash = Murmur64::from(read_u64(data).await?);
let name = lookup_hash(ctx.clone(), hash, HashGroup::Filename).await; let name = ctx.lookup_hash(hash, HashGroup::Filename);
tracing::trace!(index = i, r"type" = ?t, %hash, name, "Package entry"); tracing::trace!(index = i, r"type" = ?t, %hash, name, "Package entry");