1mod cache;
4mod common;
5mod deno_dir;
6#[cfg(feature = "file_fetcher")]
7pub mod file_fetcher;
8mod global;
9mod local;
10pub mod memory;
11pub mod npm;
12mod sync;
13
14pub const CACHE_PERM: u32 = 0o644;
16
17pub use cache::CacheEntry;
18pub use cache::CacheReadFileError;
19pub use cache::Checksum;
20pub use cache::ChecksumIntegrityError;
21pub use cache::GlobalOrLocalHttpCache;
22pub use cache::GlobalToLocalCopy;
23pub use cache::HttpCache;
24pub use cache::HttpCacheItemKey;
25pub use cache::HttpCacheRc;
26pub use cache::SerializedCachedUrlMetadata;
27pub use cache::url_to_filename;
28pub use common::HeadersMap;
29pub use deno_dir::DenoDirResolutionError;
30pub use deno_dir::ResolveDenoDirSys;
31pub use deno_dir::resolve_deno_dir;
32pub use global::GlobalHttpCache;
33pub use global::GlobalHttpCacheRc;
34pub use global::GlobalHttpCacheSys;
35pub use local::LocalHttpCache;
36pub use local::LocalHttpCacheRc;
37pub use local::LocalHttpCacheSys;
38pub use local::LocalLspHttpCache;
39
40#[cfg(feature = "wasm")]
41pub mod wasm {
42 use std::collections::HashMap;
43 use std::io::ErrorKind;
44 use std::path::PathBuf;
45
46 use js_sys::Object;
47 use js_sys::Reflect;
48 use js_sys::Uint8Array;
49 use sys_traits::EnvVar;
50 use sys_traits::impls::RealSys;
51 use sys_traits::impls::wasm_path_to_str;
52 use sys_traits::impls::wasm_string_to_path;
53 use url::Url;
54 use wasm_bindgen::prelude::*;
55
56 use crate::CacheReadFileError;
57 use crate::Checksum;
58 use crate::HttpCache;
59 use crate::cache::CacheEntry;
60 use crate::cache::GlobalToLocalCopy;
61 use crate::common::HeadersMap;
62 use crate::deno_dir;
63 use crate::sync::new_rc;
64
65 #[wasm_bindgen]
66 pub fn url_to_filename(url: &str) -> Result<String, JsValue> {
67 console_error_panic_hook::set_once();
68 let url = parse_url(url).map_err(as_js_error)?;
69 crate::cache::url_to_filename(&url)
70 .map(|s| s.to_string_lossy().to_string())
71 .map_err(as_js_error)
72 }
73
74 #[wasm_bindgen]
75 pub fn resolve_deno_dir(
76 maybe_custom_root: Option<String>,
77 ) -> Result<String, JsValue> {
78 console_error_panic_hook::set_once();
79 deno_dir::resolve_deno_dir(
80 &RealSys,
81 maybe_custom_root.map(wasm_string_to_path),
82 )
83 .map(|path| wasm_path_to_str(&path).into_owned())
84 .map_err(|e| JsValue::from(js_sys::Error::new(&e.to_string())))
85 }
86
87 #[wasm_bindgen]
88 pub struct GlobalHttpCache {
89 cache: crate::GlobalHttpCache<RealSys>,
90 }
91
92 #[wasm_bindgen]
93 impl GlobalHttpCache {
94 pub fn new(path: &str) -> Self {
95 Self {
96 cache: crate::GlobalHttpCache::new(RealSys, PathBuf::from(path)),
97 }
98 }
99
100 #[wasm_bindgen(js_name = getHeaders)]
101 pub fn get_headers(&self, url: &str) -> Result<JsValue, JsValue> {
102 get_headers(&self.cache, url)
103 }
104
105 pub fn get(
106 &self,
107 url: &str,
108 maybe_checksum: Option<String>,
109 ) -> Result<JsValue, JsValue> {
110 get_cache_entry(&self.cache, url, maybe_checksum.as_deref())
111 }
112
113 pub fn set(
114 &self,
115 url: &str,
116 headers: JsValue,
117 text: &[u8],
118 ) -> Result<(), JsValue> {
119 set(&self.cache, url, headers, text)
120 }
121 }
122
123 #[wasm_bindgen]
124 pub struct LocalHttpCache {
125 cache: crate::LocalHttpCache<RealSys>,
126 }
127
128 #[wasm_bindgen]
129 impl LocalHttpCache {
130 pub fn new(
131 local_path: String,
132 global_path: String,
133 allow_global_to_local_copy: bool,
134 ) -> Self {
135 console_error_panic_hook::set_once();
136 let global =
137 crate::GlobalHttpCache::new(RealSys, wasm_string_to_path(global_path));
138 let jsr_url = RealSys
139 .env_var("JSR_URL")
140 .ok()
141 .and_then(|url| {
142 let registry_url = format!("{}/", url.trim_end_matches('/'));
144 Url::parse(®istry_url).ok()
145 })
146 .unwrap_or_else(|| Url::parse("https://jsr.io/").unwrap());
147 let local = crate::LocalHttpCache::new(
148 wasm_string_to_path(local_path),
149 new_rc(global),
150 if allow_global_to_local_copy {
151 GlobalToLocalCopy::Allow
152 } else {
153 GlobalToLocalCopy::Disallow
154 },
155 jsr_url,
156 );
157 Self { cache: local }
158 }
159
160 #[wasm_bindgen(js_name = getHeaders)]
161 pub fn get_headers(&self, url: &str) -> Result<JsValue, JsValue> {
162 get_headers(&self.cache, url)
163 }
164
165 pub fn get(
166 &self,
167 url: &str,
168 maybe_checksum: Option<String>,
169 ) -> Result<JsValue, JsValue> {
170 get_cache_entry(&self.cache, url, maybe_checksum.as_deref())
171 }
172
173 pub fn set(
174 &self,
175 url: &str,
176 headers: JsValue,
177 text: &[u8],
178 ) -> Result<(), JsValue> {
179 set(&self.cache, url, headers, text)
180 }
181 }
182
183 fn get_headers<Cache: HttpCache>(
184 cache: &Cache,
185 url: &str,
186 ) -> Result<JsValue, JsValue> {
187 fn inner<Cache: HttpCache>(
188 cache: &Cache,
189 url: &str,
190 ) -> std::io::Result<Option<HeadersMap>> {
191 let url = parse_url(url)?;
192 let key = cache.cache_item_key(&url)?;
193 cache.read_headers(&key)
194 }
195
196 inner(cache, url)
197 .map(|headers| match headers {
198 Some(headers) => serde_wasm_bindgen::to_value(&headers).unwrap(),
199 None => JsValue::undefined(),
200 })
201 .map_err(as_js_error)
202 }
203
204 fn get_cache_entry<Cache: HttpCache>(
205 cache: &Cache,
206 url: &str,
207 maybe_checksum: Option<&str>,
208 ) -> Result<JsValue, JsValue> {
209 fn inner<Cache: HttpCache>(
210 cache: &Cache,
211 url: &str,
212 maybe_checksum: Option<Checksum>,
213 ) -> std::io::Result<Option<CacheEntry>> {
214 let url = parse_url(url)?;
215 let key = cache.cache_item_key(&url)?;
216 match cache.get(&key, maybe_checksum) {
217 Ok(Some(entry)) => Ok(Some(entry)),
218 Ok(None) => Ok(None),
219 Err(err) => match err {
220 CacheReadFileError::Io(err) => Err(err),
221 CacheReadFileError::ChecksumIntegrity(err) => {
222 Err(std::io::Error::new(ErrorKind::InvalidData, err.to_string()))
223 }
224 },
225 }
226 }
227
228 inner(cache, url, maybe_checksum.map(Checksum::new))
229 .map(|text| match text {
230 Some(entry) => {
231 let content = {
232 let array = Uint8Array::new_with_length(entry.content.len() as u32);
233 array.copy_from(&entry.content);
234 JsValue::from(array)
235 };
236 let headers: JsValue = {
237 let headers_object = Object::new();
239 for (key, value) in &entry.metadata.headers {
240 Reflect::set(
241 &headers_object,
242 &JsValue::from_str(key),
243 &JsValue::from_str(value),
244 )
245 .unwrap();
246 }
247 JsValue::from(headers_object)
248 };
249 let obj = Object::new();
250 Reflect::set(&obj, &JsValue::from_str("content"), &content).unwrap();
251 Reflect::set(&obj, &JsValue::from_str("headers"), &headers).unwrap();
252 JsValue::from(obj)
253 }
254 None => JsValue::undefined(),
255 })
256 .map_err(as_js_error)
257 }
258
259 fn set<Cache: HttpCache>(
260 cache: &Cache,
261 url: &str,
262 headers: JsValue,
263 content: &[u8],
264 ) -> Result<(), JsValue> {
265 fn inner<Cache: HttpCache>(
266 cache: &Cache,
267 url: &str,
268 headers: JsValue,
269 content: &[u8],
270 ) -> std::io::Result<()> {
271 let url = parse_url(url)?;
272 let headers: HashMap<String, String> =
273 serde_wasm_bindgen::from_value(headers).map_err(|err| {
274 std::io::Error::new(ErrorKind::InvalidData, err.to_string())
275 })?;
276 cache.set(&url, headers, content)
277 }
278
279 inner(cache, url, headers, content).map_err(as_js_error)
280 }
281
282 fn parse_url(url: &str) -> std::io::Result<Url> {
283 Url::parse(url)
284 .map_err(|e| std::io::Error::new(ErrorKind::InvalidInput, e.to_string()))
285 }
286
287 fn as_js_error(e: std::io::Error) -> JsValue {
288 JsValue::from(js_sys::Error::new(&e.to_string()))
289 }
290}