1use super::*;
2
3pub(crate) fn set_global_state(state: Arc<AppState>) -> Result<(), EuvError> {
13 APP_STATE.set(state).map_err(|_: Arc<AppState>| {
14 EuvError::Message(ERROR_GLOBAL_STATE_ALREADY_INITIALIZED.to_string())
15 })
16}
17
18pub(crate) fn get_global_state() -> Option<Arc<AppState>> {
24 APP_STATE.get().cloned()
25}
26
27async fn resolve_inline_js(config: &HtmlConfig) -> String {
48 if inline_bridge_disabled() {
49 return build_module_fallback_bridge(config.get_import_path());
50 }
51 let pkg_dir: PathBuf = config.get_serving_root().join(PKG_DIR_NAME);
52 let js_name: String = config
53 .get_import_path()
54 .rsplit('/')
55 .next()
56 .unwrap_or("")
57 .to_string();
58 if js_name.is_empty() {
59 return build_module_fallback_bridge(config.get_import_path());
60 }
61 let js_path: PathBuf = pkg_dir.join(&js_name);
62 if !js_path.exists() {
63 return build_module_fallback_bridge(config.get_import_path());
64 }
65 let wasm_url: String = if let Some(stem) = js_name.strip_suffix(".js") {
66 format!("pkg/{stem}_bg.wasm")
67 } else {
68 config
69 .get_import_path()
70 .replace(JS_EXTENSION, WASM_FILE_SUFFIX)
71 };
72 match build_inline_bridge(&pkg_dir, &js_name, &wasm_url).await {
73 Ok(snippet) => snippet,
74 Err(error) => {
75 log::warn!("Falling back to module import bridge: {error}");
76 build_module_fallback_bridge(config.get_import_path())
77 }
78 }
79}
80
81pub(crate) async fn generate_html(config: &HtmlConfig) -> Result<String, EuvError> {
103 let template_content: String = if let Some(custom_path) = config.try_get_custom_index_html() {
104 let bytes: Vec<u8> =
105 read(custom_path)
106 .await
107 .map_err(|error: io::Error| EuvError::IoPath {
108 message: ERROR_READ_CUSTOM_INDEX_HTML.to_string(),
109 path: custom_path.to_path_buf(),
110 error,
111 })?;
112 String::from_utf8(bytes).map_err(|error: FromUtf8Error| EuvError::Utf8 {
113 message: ERROR_CUSTOM_INDEX_HTML_NOT_UTF8.to_string(),
114 error,
115 })?
116 } else if config.get_is_release() {
117 INDEX_HTML_RELEASE.to_string()
118 } else {
119 INDEX_HTML_DEV.to_string()
120 };
121 let inline_js: String = resolve_inline_js(config).await;
122 let base_href_tag: String = if config.get_is_dev_server() {
123 format!(
124 "<base href=\"/{}/\" />",
125 config
126 .get_serving_root()
127 .file_name()
128 .and_then(|name: &ffi::OsStr| name.to_str())
129 .unwrap_or("")
130 )
131 } else {
132 String::new()
133 };
134 let html: String = template_content
135 .replace(BASE_HREF_PLACEHOLDER, &base_href_tag)
136 .replace(IMPORT_PATH_PLACEHOLDER, config.get_import_path())
137 .replace(RELOAD_ROUTE_PLACEHOLDER, RELOAD_ROUTE)
138 .replace(INLINE_JS_PLACEHOLDER, &inline_js)
139 .replace(LOADING_STYLE_PLACEHOLDER, LOADING_STYLE)
140 .replace(LOADING_ELEMENT_PLACEHOLDER, LOADING_ELEMENT)
141 .replace(LOADING_REMOVAL_PLACEHOLDER, LOADING_REMOVAL_SCRIPT);
142 let index_path: PathBuf = config.get_serving_root().join(INDEX_HTML_FILE_NAME);
143 create_dir_all(config.get_serving_root())
144 .await
145 .map_err(|error: io::Error| EuvError::Io {
146 message: ERROR_CREATE_STATIC_DIRECTORY.to_string(),
147 error,
148 })?;
149 write(&index_path, &html)
150 .await
151 .map_err(|error: io::Error| EuvError::Io {
152 message: ERROR_WRITE_INDEX_HTML.to_string(),
153 error,
154 })?;
155 Ok(html)
156}
157
158pub async fn resolve_www_dir(www_dir: &Path) -> PathBuf {
168 if metadata(www_dir.join(INDEX_HTML_FILE_NAME)).await.is_ok() {
169 return www_dir.to_path_buf();
170 }
171 let parent_name: Option<&str> = www_dir
172 .file_name()
173 .and_then(|file_name_os_str: &ffi::OsStr| file_name_os_str.to_str());
174 if let Some(name) = parent_name {
175 let nested: PathBuf = www_dir.join(name);
176 if metadata(nested.join(INDEX_HTML_FILE_NAME)).await.is_ok() {
177 return nested;
178 }
179 }
180 www_dir.to_path_buf()
181}
182
183pub fn resolve_pkg_dir(args: &ModeArgs) -> PathBuf {
196 resolve_out_dir(args)
197}
198
199pub async fn resolve_file_in_base(base: &Path, path: &str) -> Option<PathBuf> {
213 let file_path: PathBuf = base.join(path);
214 let canonical_path: PathBuf = canonicalize(&file_path).await.ok()?;
215 let base_canonical: PathBuf = canonicalize(base).await.ok()?;
216 canonical_path
217 .starts_with(&base_canonical)
218 .then_some(file_path)
219}