mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-29 09:08:58 +00:00
conditional compilation of async compat (#95)
Problems with the previous code: - `async-compat` is necessary for headless mode (cli server rendering) to load remote scenes from the API without blowing up. Without it, the code complains about the lack of a Tokio runtime. - Unfortunately, `async-compat` doesn't work with WASM and the entire web build is broken by its presence. This change introduces conditional compilation so `async-compat` is only leveraged in headless mode.
This commit is contained in:
@@ -15,6 +15,7 @@ path = "src/main.rs"
|
|||||||
[[bin]]
|
[[bin]]
|
||||||
name = "studio-headless"
|
name = "studio-headless"
|
||||||
path = "src/main-headless.rs"
|
path = "src/main-headless.rs"
|
||||||
|
required-features = ["headless_cli"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy-inspector-egui = "0.22.0"
|
bevy-inspector-egui = "0.22.0"
|
||||||
@@ -69,6 +70,7 @@ wasm = [
|
|||||||
"bevy_rapier3d/wasm-bindgen",
|
"bevy_rapier3d/wasm-bindgen",
|
||||||
]
|
]
|
||||||
desktop = []
|
desktop = []
|
||||||
|
headless_cli = []
|
||||||
|
|
||||||
[dependencies.bevy]
|
[dependencies.bevy]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|||||||
+75
-61
@@ -16,6 +16,71 @@ pub struct RemoteAssetReader;
|
|||||||
impl RemoteAssetReader {
|
impl RemoteAssetReader {
|
||||||
const API_BASE_URL: &'static str = "https://api.fakeyou.com/v1/media_files/file";
|
const API_BASE_URL: &'static str = "https://api.fakeyou.com/v1/media_files/file";
|
||||||
const BUCKET_BASE_URL: &'static str = "https://storage.googleapis.com/vocodes-public";
|
const BUCKET_BASE_URL: &'static str = "https://storage.googleapis.com/vocodes-public";
|
||||||
|
|
||||||
|
async fn load<'a>(
|
||||||
|
&'a self,
|
||||||
|
path: &'a Path,
|
||||||
|
) -> Result<Box<Reader<'a>>, AssetReaderError> {
|
||||||
|
let token = path
|
||||||
|
.ext_file_prefix()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
AssetReaderError::Io(std::io::Error::new(
|
||||||
|
ErrorKind::Other,
|
||||||
|
format!("Failed to parse token from '{path:?}'"),
|
||||||
|
))
|
||||||
|
})?
|
||||||
|
.to_str()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
info!("Loading asset from media token: '{token}'");
|
||||||
|
|
||||||
|
let response = reqwest::get(format!("{}/{token}", &Self::API_BASE_URL))
|
||||||
|
.await
|
||||||
|
.map_err(IntoError::<AssetReaderError>::into)?;
|
||||||
|
|
||||||
|
let response = match response.status() {
|
||||||
|
StatusCode::OK => response
|
||||||
|
.json::<GetMediaFileSuccessResponse>()
|
||||||
|
.await
|
||||||
|
.map_err(IntoError::<AssetReaderError>::into),
|
||||||
|
other => Err(AssetReaderError::Io(std::io::Error::new(
|
||||||
|
ErrorKind::Other,
|
||||||
|
format!("Status Code from endpoint: {other}"),
|
||||||
|
))),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
let url = format!(
|
||||||
|
"{}{}",
|
||||||
|
&Self::BUCKET_BASE_URL,
|
||||||
|
&response.media_file.public_bucket_path
|
||||||
|
);
|
||||||
|
|
||||||
|
let response = reqwest::get(url)
|
||||||
|
.await
|
||||||
|
.map_err(IntoError::<AssetReaderError>::into)?;
|
||||||
|
|
||||||
|
let bytes = match response.status() {
|
||||||
|
// TODO: This is not thread-safe, but some variation of this
|
||||||
|
// would be better than the current solution once Bevy
|
||||||
|
// WASM becomes multi-threaded:
|
||||||
|
// StatusCode::OK => Ok(response.bytes_stream().map(|result| {
|
||||||
|
// result.map_err(|err| std::io::Error::new(ErrorKind::Other, format!("{err}")))
|
||||||
|
// })),
|
||||||
|
StatusCode::OK => Ok(response
|
||||||
|
.bytes()
|
||||||
|
.await
|
||||||
|
.map_err(IntoError::<AssetReaderError>::into)?
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Vec<_>>()),
|
||||||
|
other => Err(AssetReaderError::Io(std::io::Error::new(
|
||||||
|
ErrorKind::Other,
|
||||||
|
format!("Status Code from bucket URL: {other}"),
|
||||||
|
))),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
let reader: Box<Reader> = Box::new(VecReader::new(bytes));
|
||||||
|
Ok(reader)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AssetReader for RemoteAssetReader {
|
impl AssetReader for RemoteAssetReader {
|
||||||
@@ -23,67 +88,16 @@ impl AssetReader for RemoteAssetReader {
|
|||||||
&'a self,
|
&'a self,
|
||||||
path: &'a Path,
|
path: &'a Path,
|
||||||
) -> BoxedFuture<'a, Result<Box<Reader<'a>>, AssetReaderError>> {
|
) -> BoxedFuture<'a, Result<Box<Reader<'a>>, AssetReaderError>> {
|
||||||
Box::pin(Compat::new(async move {
|
let unboxed = async move {
|
||||||
let token = path
|
self.load(path).await
|
||||||
.ext_file_prefix()
|
};
|
||||||
.ok_or_else(|| {
|
if cfg!(headless_cli) {
|
||||||
AssetReaderError::Io(std::io::Error::new(
|
// NB: Headless mode (server rendering) is running without a Tokio runtime.
|
||||||
ErrorKind::Other,
|
// The reqwest HTTP client requires async-compat to function at runtime.
|
||||||
format!("Failed to parse token from '{path:?}'"),
|
Box::pin(Compat::new(unboxed))
|
||||||
))
|
} else {
|
||||||
})?
|
Box::pin(unboxed)
|
||||||
.to_str()
|
}
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
info!("Loading asset from media token: '{token}'");
|
|
||||||
|
|
||||||
let response = reqwest::get(format!("{}/{token}", &Self::API_BASE_URL))
|
|
||||||
.await
|
|
||||||
.map_err(IntoError::<AssetReaderError>::into)?;
|
|
||||||
|
|
||||||
let response = match response.status() {
|
|
||||||
StatusCode::OK => response
|
|
||||||
.json::<GetMediaFileSuccessResponse>()
|
|
||||||
.await
|
|
||||||
.map_err(IntoError::<AssetReaderError>::into),
|
|
||||||
other => Err(AssetReaderError::Io(std::io::Error::new(
|
|
||||||
ErrorKind::Other,
|
|
||||||
format!("Status Code from endpoint: {other}"),
|
|
||||||
))),
|
|
||||||
}?;
|
|
||||||
|
|
||||||
let url = format!(
|
|
||||||
"{}{}",
|
|
||||||
&Self::BUCKET_BASE_URL,
|
|
||||||
&response.media_file.public_bucket_path
|
|
||||||
);
|
|
||||||
|
|
||||||
let response = reqwest::get(url)
|
|
||||||
.await
|
|
||||||
.map_err(IntoError::<AssetReaderError>::into)?;
|
|
||||||
|
|
||||||
let bytes = match response.status() {
|
|
||||||
// TODO: This is not thread-safe, but some variation of this
|
|
||||||
// would be better than the current solution once Bevy
|
|
||||||
// WASM becomes multi-threaded:
|
|
||||||
// StatusCode::OK => Ok(response.bytes_stream().map(|result| {
|
|
||||||
// result.map_err(|err| std::io::Error::new(ErrorKind::Other, format!("{err}")))
|
|
||||||
// })),
|
|
||||||
StatusCode::OK => Ok(response
|
|
||||||
.bytes()
|
|
||||||
.await
|
|
||||||
.map_err(IntoError::<AssetReaderError>::into)?
|
|
||||||
.into_iter()
|
|
||||||
.collect::<Vec<_>>()),
|
|
||||||
other => Err(AssetReaderError::Io(std::io::Error::new(
|
|
||||||
ErrorKind::Other,
|
|
||||||
format!("Status Code from bucket URL: {other}"),
|
|
||||||
))),
|
|
||||||
}?;
|
|
||||||
|
|
||||||
let reader: Box<Reader> = Box::new(VecReader::new(bytes));
|
|
||||||
Ok(reader)
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_meta<'a>(
|
fn read_meta<'a>(
|
||||||
|
|||||||
Reference in New Issue
Block a user