use super::*;
pub(crate) fn set_global_state(state: Arc<AppState>) -> Result<(), EuvError> {
APP_STATE.set(state).map_err(|_: Arc<AppState>| {
EuvError::Message(String::from("Global state already initialized"))
})
}
pub(crate) fn get_global_state() -> Option<Arc<AppState>> {
APP_STATE.get().cloned()
}
async fn resolve_inline_js(config: &HtmlConfig) -> String {
if inline_bridge_disabled() {
return build_module_fallback_bridge(config.get_import_path());
}
let pkg_dir: PathBuf = config.get_serving_root().join(PKG_DIR_NAME);
let js_name: String = config
.get_import_path()
.rsplit('/')
.next()
.unwrap_or("")
.to_string();
if js_name.is_empty() {
return build_module_fallback_bridge(config.get_import_path());
}
let js_path: PathBuf = pkg_dir.join(&js_name);
if !js_path.exists() {
return build_module_fallback_bridge(config.get_import_path());
}
let wasm_url: String = if let Some(stem) = js_name.strip_suffix(".js") {
format!("pkg/{stem}_bg.wasm")
} else {
config.get_import_path().replace(".js", "_bg.wasm")
};
match build_inline_bridge(&pkg_dir, &js_name, &wasm_url).await {
Ok(snippet) => snippet,
Err(error) => {
log::warn!("Falling back to module import bridge: {error}");
build_module_fallback_bridge(config.get_import_path())
}
}
}
pub(crate) async fn generate_html(config: &HtmlConfig) -> Result<String, EuvError> {
let template_content: String = if let Some(custom_path) = config.try_get_custom_index_html() {
let bytes: Vec<u8> =
read(custom_path)
.await
.map_err(|error: io::Error| EuvError::IoPath {
message: String::from("Failed to read custom index.html"),
path: custom_path.to_path_buf(),
error,
})?;
String::from_utf8(bytes).map_err(|error: FromUtf8Error| EuvError::Utf8 {
message: String::from("Custom index.html is not valid UTF-8"),
error,
})?
} else if config.get_is_release() {
INDEX_HTML_RELEASE.to_string()
} else {
INDEX_HTML_DEV.to_string()
};
let inline_js: String = resolve_inline_js(config).await;
let html: String = template_content
.replace(IMPORT_PATH_PLACEHOLDER, config.get_import_path())
.replace(RELOAD_ROUTE_PLACEHOLDER, RELOAD_ROUTE)
.replace(INLINE_JS_PLACEHOLDER, &inline_js);
let index_path: PathBuf = config.get_serving_root().join(INDEX_HTML_FILE_NAME);
create_dir_all(config.get_serving_root())
.await
.map_err(|error: io::Error| EuvError::Io {
message: String::from("Failed to create static directory"),
error,
})?;
write(&index_path, &html)
.await
.map_err(|error: io::Error| EuvError::Io {
message: String::from("Failed to write index.html"),
error,
})?;
Ok(html)
}
pub async fn resolve_www_dir(www_dir: &Path) -> PathBuf {
if metadata(www_dir.join(INDEX_HTML_FILE_NAME)).await.is_ok() {
return www_dir.to_path_buf();
}
let parent_name: Option<&str> = www_dir
.file_name()
.and_then(|file_name_os_str: &ffi::OsStr| file_name_os_str.to_str());
if let Some(name) = parent_name {
let nested: PathBuf = www_dir.join(name);
if metadata(nested.join(INDEX_HTML_FILE_NAME)).await.is_ok() {
return nested;
}
}
www_dir.to_path_buf()
}
pub fn resolve_pkg_dir(args: &ModeArgs) -> PathBuf {
resolve_out_dir(args)
}
pub async fn resolve_file_in_base(base: &Path, path: &str) -> Option<PathBuf> {
let file_path: PathBuf = base.join(path);
let canonical_path: PathBuf = canonicalize(&file_path).await.ok()?;
let base_canonical: PathBuf = canonicalize(base).await.ok()?;
canonical_path
.starts_with(&base_canonical)
.then_some(file_path)
}