mirror of
https://github.com/denoland/deno.git
synced 2025-01-12 00:54:02 -05:00
feat: blob URL support (#10045)
This commit adds blob URL support. Blob URLs are stored in a process global storage, that can be accessed from all workers, and the module loader. Blob URLs can be created using `URL.createObjectURL` and revoked using `URL.revokeObjectURL`. This commit does not add support for `fetch`ing blob URLs. This will be added in a follow up commit.
This commit is contained in:
parent
2865f39bec
commit
966ce7de8a
33 changed files with 488 additions and 33 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -621,6 +621,7 @@ name = "deno_file"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"deno_core",
|
"deno_core",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -67,7 +67,7 @@ impl DiskCache {
|
||||||
out.push(path_seg);
|
out.push(path_seg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"http" | "https" | "data" => out = url_to_filename(url)?,
|
"http" | "https" | "data" | "blob" => out = url_to_filename(url)?,
|
||||||
"file" => {
|
"file" => {
|
||||||
let path = match url.to_file_path() {
|
let path = match url.to_file_path() {
|
||||||
Ok(path) => path,
|
Ok(path) => path,
|
||||||
|
|
|
@ -18,9 +18,11 @@ use deno_core::futures;
|
||||||
use deno_core::futures::future::FutureExt;
|
use deno_core::futures::future::FutureExt;
|
||||||
use deno_core::ModuleSpecifier;
|
use deno_core::ModuleSpecifier;
|
||||||
use deno_runtime::deno_fetch::reqwest;
|
use deno_runtime::deno_fetch::reqwest;
|
||||||
|
use deno_runtime::deno_file::BlobUrlStore;
|
||||||
use deno_runtime::permissions::Permissions;
|
use deno_runtime::permissions::Permissions;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
use std::borrow::Borrow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
@ -32,7 +34,8 @@ use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
static DENO_AUTH_TOKENS: &str = "DENO_AUTH_TOKENS";
|
static DENO_AUTH_TOKENS: &str = "DENO_AUTH_TOKENS";
|
||||||
pub const SUPPORTED_SCHEMES: [&str; 4] = ["data", "file", "http", "https"];
|
pub const SUPPORTED_SCHEMES: [&str; 5] =
|
||||||
|
["data", "blob", "file", "http", "https"];
|
||||||
|
|
||||||
/// A structure representing a source file.
|
/// A structure representing a source file.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
@ -317,6 +320,7 @@ pub struct FileFetcher {
|
||||||
cache_setting: CacheSetting,
|
cache_setting: CacheSetting,
|
||||||
http_cache: HttpCache,
|
http_cache: HttpCache,
|
||||||
http_client: reqwest::Client,
|
http_client: reqwest::Client,
|
||||||
|
blob_url_store: BlobUrlStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileFetcher {
|
impl FileFetcher {
|
||||||
|
@ -325,6 +329,7 @@ impl FileFetcher {
|
||||||
cache_setting: CacheSetting,
|
cache_setting: CacheSetting,
|
||||||
allow_remote: bool,
|
allow_remote: bool,
|
||||||
ca_data: Option<Vec<u8>>,
|
ca_data: Option<Vec<u8>>,
|
||||||
|
blob_url_store: BlobUrlStore,
|
||||||
) -> Result<Self, AnyError> {
|
) -> Result<Self, AnyError> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
auth_tokens: AuthTokens::new(env::var(DENO_AUTH_TOKENS).ok()),
|
auth_tokens: AuthTokens::new(env::var(DENO_AUTH_TOKENS).ok()),
|
||||||
|
@ -333,6 +338,7 @@ impl FileFetcher {
|
||||||
cache_setting,
|
cache_setting,
|
||||||
http_cache,
|
http_cache,
|
||||||
http_client: create_http_client(get_user_agent(), ca_data)?,
|
http_client: create_http_client(get_user_agent(), ca_data)?,
|
||||||
|
blob_url_store,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,6 +452,62 @@ impl FileFetcher {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a blob URL.
|
||||||
|
fn fetch_blob_url(
|
||||||
|
&self,
|
||||||
|
specifier: &ModuleSpecifier,
|
||||||
|
) -> Result<File, AnyError> {
|
||||||
|
debug!("FileFetcher::fetch_blob_url() - specifier: {}", specifier);
|
||||||
|
match self.fetch_cached(specifier, 0) {
|
||||||
|
Ok(Some(file)) => return Ok(file),
|
||||||
|
Ok(None) => {}
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.cache_setting == CacheSetting::Only {
|
||||||
|
return Err(custom_error(
|
||||||
|
"NotFound",
|
||||||
|
format!(
|
||||||
|
"Specifier not found in cache: \"{}\", --cached-only is specified.",
|
||||||
|
specifier
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let blob_url_storage = self.blob_url_store.borrow();
|
||||||
|
let blob = blob_url_storage.get(specifier)?.ok_or_else(|| {
|
||||||
|
custom_error(
|
||||||
|
"NotFound",
|
||||||
|
format!("Blob URL not found: \"{}\".", specifier),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let content_type = blob.media_type;
|
||||||
|
|
||||||
|
let (media_type, maybe_charset) =
|
||||||
|
map_content_type(specifier, Some(content_type.clone()));
|
||||||
|
let source =
|
||||||
|
strip_shebang(get_source_from_bytes(blob.data, maybe_charset)?);
|
||||||
|
|
||||||
|
let local =
|
||||||
|
self
|
||||||
|
.http_cache
|
||||||
|
.get_cache_filename(specifier)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
generic_error("Cannot convert specifier to cached filename.")
|
||||||
|
})?;
|
||||||
|
let mut headers = HashMap::new();
|
||||||
|
headers.insert("content-type".to_string(), content_type);
|
||||||
|
self.http_cache.set(specifier, headers, source.as_bytes())?;
|
||||||
|
|
||||||
|
Ok(File {
|
||||||
|
local,
|
||||||
|
maybe_types: None,
|
||||||
|
media_type,
|
||||||
|
source,
|
||||||
|
specifier: specifier.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
/// Asynchronously fetch remote source file specified by the URL following
|
/// Asynchronously fetch remote source file specified by the URL following
|
||||||
/// redirects.
|
/// redirects.
|
||||||
///
|
///
|
||||||
|
@ -555,6 +617,12 @@ impl FileFetcher {
|
||||||
self.cache.insert(specifier.clone(), file.clone());
|
self.cache.insert(specifier.clone(), file.clone());
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
|
} else if scheme == "blob" {
|
||||||
|
let result = self.fetch_blob_url(specifier);
|
||||||
|
if let Ok(file) = &result {
|
||||||
|
self.cache.insert(specifier.clone(), file.clone());
|
||||||
|
}
|
||||||
|
result
|
||||||
} else if !self.allow_remote {
|
} else if !self.allow_remote {
|
||||||
Err(custom_error(
|
Err(custom_error(
|
||||||
"NoRemote",
|
"NoRemote",
|
||||||
|
@ -604,6 +672,7 @@ mod tests {
|
||||||
use deno_core::error::get_custom_error_class;
|
use deno_core::error::get_custom_error_class;
|
||||||
use deno_core::resolve_url;
|
use deno_core::resolve_url;
|
||||||
use deno_core::resolve_url_or_path;
|
use deno_core::resolve_url_or_path;
|
||||||
|
use deno_runtime::deno_file::Blob;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
|
|
||||||
|
@ -611,14 +680,29 @@ mod tests {
|
||||||
cache_setting: CacheSetting,
|
cache_setting: CacheSetting,
|
||||||
maybe_temp_dir: Option<Rc<TempDir>>,
|
maybe_temp_dir: Option<Rc<TempDir>>,
|
||||||
) -> (FileFetcher, Rc<TempDir>) {
|
) -> (FileFetcher, Rc<TempDir>) {
|
||||||
|
let (file_fetcher, temp_dir, _) =
|
||||||
|
setup_with_blob_url_store(cache_setting, maybe_temp_dir);
|
||||||
|
(file_fetcher, temp_dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_with_blob_url_store(
|
||||||
|
cache_setting: CacheSetting,
|
||||||
|
maybe_temp_dir: Option<Rc<TempDir>>,
|
||||||
|
) -> (FileFetcher, Rc<TempDir>, BlobUrlStore) {
|
||||||
let temp_dir = maybe_temp_dir.unwrap_or_else(|| {
|
let temp_dir = maybe_temp_dir.unwrap_or_else(|| {
|
||||||
Rc::new(TempDir::new().expect("failed to create temp directory"))
|
Rc::new(TempDir::new().expect("failed to create temp directory"))
|
||||||
});
|
});
|
||||||
let location = temp_dir.path().join("deps");
|
let location = temp_dir.path().join("deps");
|
||||||
let file_fetcher =
|
let blob_url_store = BlobUrlStore::default();
|
||||||
FileFetcher::new(HttpCache::new(&location), cache_setting, true, None)
|
let file_fetcher = FileFetcher::new(
|
||||||
|
HttpCache::new(&location),
|
||||||
|
cache_setting,
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
blob_url_store.clone(),
|
||||||
|
)
|
||||||
.expect("setup failed");
|
.expect("setup failed");
|
||||||
(file_fetcher, temp_dir)
|
(file_fetcher, temp_dir, blob_url_store)
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! file_url {
|
macro_rules! file_url {
|
||||||
|
@ -988,6 +1072,36 @@ mod tests {
|
||||||
assert_eq!(file.specifier, specifier);
|
assert_eq!(file.specifier, specifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_fetch_blob_url() {
|
||||||
|
let (file_fetcher, _, blob_url_store) =
|
||||||
|
setup_with_blob_url_store(CacheSetting::Use, None);
|
||||||
|
|
||||||
|
let specifier = blob_url_store.insert(
|
||||||
|
Blob {
|
||||||
|
data:
|
||||||
|
"export const a = \"a\";\n\nexport enum A {\n A,\n B,\n C,\n}\n"
|
||||||
|
.as_bytes()
|
||||||
|
.to_vec(),
|
||||||
|
media_type: "application/typescript".to_string(),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = file_fetcher
|
||||||
|
.fetch(&specifier, &Permissions::allow_all())
|
||||||
|
.await;
|
||||||
|
assert!(result.is_ok());
|
||||||
|
let file = result.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
file.source,
|
||||||
|
"export const a = \"a\";\n\nexport enum A {\n A,\n B,\n C,\n}\n"
|
||||||
|
);
|
||||||
|
assert_eq!(file.media_type, MediaType::TypeScript);
|
||||||
|
assert_eq!(file.maybe_types, None);
|
||||||
|
assert_eq!(file.specifier, specifier);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_fetch_complex() {
|
async fn test_fetch_complex() {
|
||||||
let _http_server_guard = test_util::http_server();
|
let _http_server_guard = test_util::http_server();
|
||||||
|
@ -1061,6 +1175,7 @@ mod tests {
|
||||||
CacheSetting::ReloadAll,
|
CacheSetting::ReloadAll,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
|
BlobUrlStore::default(),
|
||||||
)
|
)
|
||||||
.expect("setup failed");
|
.expect("setup failed");
|
||||||
let result = file_fetcher
|
let result = file_fetcher
|
||||||
|
@ -1087,6 +1202,7 @@ mod tests {
|
||||||
CacheSetting::Use,
|
CacheSetting::Use,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
|
BlobUrlStore::default(),
|
||||||
)
|
)
|
||||||
.expect("could not create file fetcher");
|
.expect("could not create file fetcher");
|
||||||
let specifier =
|
let specifier =
|
||||||
|
@ -1114,6 +1230,7 @@ mod tests {
|
||||||
CacheSetting::Use,
|
CacheSetting::Use,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
|
BlobUrlStore::default(),
|
||||||
)
|
)
|
||||||
.expect("could not create file fetcher");
|
.expect("could not create file fetcher");
|
||||||
let result = file_fetcher_02
|
let result = file_fetcher_02
|
||||||
|
@ -1274,6 +1391,7 @@ mod tests {
|
||||||
CacheSetting::Use,
|
CacheSetting::Use,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
|
BlobUrlStore::default(),
|
||||||
)
|
)
|
||||||
.expect("could not create file fetcher");
|
.expect("could not create file fetcher");
|
||||||
let specifier =
|
let specifier =
|
||||||
|
@ -1304,6 +1422,7 @@ mod tests {
|
||||||
CacheSetting::Use,
|
CacheSetting::Use,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
|
BlobUrlStore::default(),
|
||||||
)
|
)
|
||||||
.expect("could not create file fetcher");
|
.expect("could not create file fetcher");
|
||||||
let result = file_fetcher_02
|
let result = file_fetcher_02
|
||||||
|
@ -1413,6 +1532,7 @@ mod tests {
|
||||||
CacheSetting::Use,
|
CacheSetting::Use,
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
|
BlobUrlStore::default(),
|
||||||
)
|
)
|
||||||
.expect("could not create file fetcher");
|
.expect("could not create file fetcher");
|
||||||
let specifier =
|
let specifier =
|
||||||
|
@ -1439,6 +1559,7 @@ mod tests {
|
||||||
CacheSetting::Only,
|
CacheSetting::Only,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
|
BlobUrlStore::default(),
|
||||||
)
|
)
|
||||||
.expect("could not create file fetcher");
|
.expect("could not create file fetcher");
|
||||||
let file_fetcher_02 = FileFetcher::new(
|
let file_fetcher_02 = FileFetcher::new(
|
||||||
|
@ -1446,6 +1567,7 @@ mod tests {
|
||||||
CacheSetting::Use,
|
CacheSetting::Use,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
|
BlobUrlStore::default(),
|
||||||
)
|
)
|
||||||
.expect("could not create file fetcher");
|
.expect("could not create file fetcher");
|
||||||
let specifier =
|
let specifier =
|
||||||
|
|
|
@ -39,7 +39,7 @@ fn base_url_to_filename(url: &Url) -> Option<PathBuf> {
|
||||||
};
|
};
|
||||||
out.push(host_port);
|
out.push(host_port);
|
||||||
}
|
}
|
||||||
"data" => (),
|
"data" | "blob" => (),
|
||||||
scheme => {
|
scheme => {
|
||||||
error!("Don't know how to create cache name for scheme: {}", scheme);
|
error!("Don't know how to create cache name for scheme: {}", scheme);
|
||||||
return None;
|
return None;
|
||||||
|
|
|
@ -122,6 +122,7 @@ fn create_web_worker_callback(
|
||||||
ts_version: version::TYPESCRIPT.to_string(),
|
ts_version: version::TYPESCRIPT.to_string(),
|
||||||
no_color: !colors::use_color(),
|
no_color: !colors::use_color(),
|
||||||
get_error_class_fn: Some(&crate::errors::get_error_class_name),
|
get_error_class_fn: Some(&crate::errors::get_error_class_name),
|
||||||
|
blob_url_store: program_state.blob_url_store.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut worker = WebWorker::from_options(
|
let mut worker = WebWorker::from_options(
|
||||||
|
@ -199,6 +200,7 @@ pub fn create_main_worker(
|
||||||
no_color: !colors::use_color(),
|
no_color: !colors::use_color(),
|
||||||
get_error_class_fn: Some(&crate::errors::get_error_class_name),
|
get_error_class_fn: Some(&crate::errors::get_error_class_name),
|
||||||
location: program_state.flags.location.clone(),
|
location: program_state.flags.location.clone(),
|
||||||
|
blob_url_store: program_state.blob_url_store.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut worker = MainWorker::from_options(main_module, permissions, &options);
|
let mut worker = MainWorker::from_options(main_module, permissions, &options);
|
||||||
|
|
|
@ -14,6 +14,7 @@ use crate::module_graph::TypeLib;
|
||||||
use crate::source_maps::SourceMapGetter;
|
use crate::source_maps::SourceMapGetter;
|
||||||
use crate::specifier_handler::FetchHandler;
|
use crate::specifier_handler::FetchHandler;
|
||||||
use crate::version;
|
use crate::version;
|
||||||
|
use deno_runtime::deno_file::BlobUrlStore;
|
||||||
use deno_runtime::inspector::InspectorServer;
|
use deno_runtime::inspector::InspectorServer;
|
||||||
use deno_runtime::permissions::Permissions;
|
use deno_runtime::permissions::Permissions;
|
||||||
|
|
||||||
|
@ -56,6 +57,7 @@ pub struct ProgramState {
|
||||||
pub maybe_import_map: Option<ImportMap>,
|
pub maybe_import_map: Option<ImportMap>,
|
||||||
pub maybe_inspector_server: Option<Arc<InspectorServer>>,
|
pub maybe_inspector_server: Option<Arc<InspectorServer>>,
|
||||||
pub ca_data: Option<Vec<u8>>,
|
pub ca_data: Option<Vec<u8>>,
|
||||||
|
pub blob_url_store: BlobUrlStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProgramState {
|
impl ProgramState {
|
||||||
|
@ -80,11 +82,14 @@ impl ProgramState {
|
||||||
CacheSetting::Use
|
CacheSetting::Use
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let blob_url_store = BlobUrlStore::default();
|
||||||
|
|
||||||
let file_fetcher = FileFetcher::new(
|
let file_fetcher = FileFetcher::new(
|
||||||
http_cache,
|
http_cache,
|
||||||
cache_usage,
|
cache_usage,
|
||||||
!flags.no_remote,
|
!flags.no_remote,
|
||||||
ca_data.clone(),
|
ca_data.clone(),
|
||||||
|
blob_url_store.clone(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let lockfile = if let Some(filename) = &flags.lock {
|
let lockfile = if let Some(filename) = &flags.lock {
|
||||||
|
@ -131,6 +136,7 @@ impl ProgramState {
|
||||||
maybe_import_map,
|
maybe_import_map,
|
||||||
maybe_inspector_server,
|
maybe_inspector_server,
|
||||||
ca_data,
|
ca_data,
|
||||||
|
blob_url_store,
|
||||||
};
|
};
|
||||||
Ok(Arc::new(program_state))
|
Ok(Arc::new(program_state))
|
||||||
}
|
}
|
||||||
|
@ -257,7 +263,7 @@ impl ProgramState {
|
||||||
match url.scheme() {
|
match url.scheme() {
|
||||||
// we should only be looking for emits for schemes that denote external
|
// we should only be looking for emits for schemes that denote external
|
||||||
// modules, which the disk_cache supports
|
// modules, which the disk_cache supports
|
||||||
"wasm" | "file" | "http" | "https" | "data" => (),
|
"wasm" | "file" | "http" | "https" | "data" | "blob" => (),
|
||||||
_ => {
|
_ => {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,6 +142,7 @@ pub fn get_orig_position<G: SourceMapGetter>(
|
||||||
// around it. Use the `file_name` we get from V8 if
|
// around it. Use the `file_name` we get from V8 if
|
||||||
// `source_file_name` does not parse as a URL.
|
// `source_file_name` does not parse as a URL.
|
||||||
let file_name = match deno_core::resolve_url(source_file_name) {
|
let file_name = match deno_core::resolve_url(source_file_name) {
|
||||||
|
Ok(m) if m.scheme() == "blob" => file_name,
|
||||||
Ok(m) => m.to_string(),
|
Ok(m) => m.to_string(),
|
||||||
Err(_) => file_name,
|
Err(_) => file_name,
|
||||||
};
|
};
|
||||||
|
|
|
@ -306,7 +306,9 @@ impl SpecifierHandler for FetchHandler {
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
let url = &source_file.specifier;
|
let url = &source_file.specifier;
|
||||||
let is_remote = !(url.scheme() == "file" || url.scheme() == "data");
|
let is_remote = !(url.scheme() == "file"
|
||||||
|
|| url.scheme() == "data"
|
||||||
|
|| url.scheme() == "blob");
|
||||||
let filename = disk_cache.get_cache_filename_with_extension(url, "meta");
|
let filename = disk_cache.get_cache_filename_with_extension(url, "meta");
|
||||||
let maybe_version = if let Some(filename) = filename {
|
let maybe_version = if let Some(filename) = filename {
|
||||||
if let Ok(bytes) = disk_cache.get(&filename) {
|
if let Ok(bytes) = disk_cache.get(&filename) {
|
||||||
|
@ -569,6 +571,7 @@ pub mod tests {
|
||||||
use crate::file_fetcher::CacheSetting;
|
use crate::file_fetcher::CacheSetting;
|
||||||
use crate::http_cache::HttpCache;
|
use crate::http_cache::HttpCache;
|
||||||
use deno_core::resolve_url_or_path;
|
use deno_core::resolve_url_or_path;
|
||||||
|
use deno_runtime::deno_file::BlobUrlStore;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
|
|
||||||
macro_rules! map (
|
macro_rules! map (
|
||||||
|
@ -593,6 +596,7 @@ pub mod tests {
|
||||||
CacheSetting::Use,
|
CacheSetting::Use,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
|
BlobUrlStore::default(),
|
||||||
)
|
)
|
||||||
.expect("could not setup");
|
.expect("could not setup");
|
||||||
let disk_cache = deno_dir.gen_cache;
|
let disk_cache = deno_dir.gen_cache;
|
||||||
|
|
|
@ -15,6 +15,7 @@ use deno_core::v8_set_flags;
|
||||||
use deno_core::ModuleLoader;
|
use deno_core::ModuleLoader;
|
||||||
use deno_core::ModuleSpecifier;
|
use deno_core::ModuleSpecifier;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
|
use deno_runtime::deno_file::BlobUrlStore;
|
||||||
use deno_runtime::permissions::Permissions;
|
use deno_runtime::permissions::Permissions;
|
||||||
use deno_runtime::permissions::PermissionsOptions;
|
use deno_runtime::permissions::PermissionsOptions;
|
||||||
use deno_runtime::worker::MainWorker;
|
use deno_runtime::worker::MainWorker;
|
||||||
|
@ -158,6 +159,7 @@ pub async fn run(
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let main_module = resolve_url(SPECIFIER)?;
|
let main_module = resolve_url(SPECIFIER)?;
|
||||||
let permissions = Permissions::from_options(&metadata.permissions);
|
let permissions = Permissions::from_options(&metadata.permissions);
|
||||||
|
let blob_url_store = BlobUrlStore::default();
|
||||||
let module_loader = Rc::new(EmbeddedModuleLoader(source_code));
|
let module_loader = Rc::new(EmbeddedModuleLoader(source_code));
|
||||||
let create_web_worker_cb = Arc::new(|_| {
|
let create_web_worker_cb = Arc::new(|_| {
|
||||||
todo!("Worker are currently not supported in standalone binaries");
|
todo!("Worker are currently not supported in standalone binaries");
|
||||||
|
@ -189,6 +191,7 @@ pub async fn run(
|
||||||
no_color: !colors::use_color(),
|
no_color: !colors::use_color(),
|
||||||
get_error_class_fn: Some(&get_error_class_name),
|
get_error_class_fn: Some(&get_error_class_name),
|
||||||
location: metadata.location,
|
location: metadata.location,
|
||||||
|
blob_url_store,
|
||||||
};
|
};
|
||||||
let mut worker =
|
let mut worker =
|
||||||
MainWorker::from_options(main_module.clone(), permissions, &options);
|
MainWorker::from_options(main_module.clone(), permissions, &options);
|
||||||
|
|
13
cli/tests/import_blob_url.ts
Normal file
13
cli/tests/import_blob_url.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
const blob = new Blob(
|
||||||
|
['export const a = "a";\n\nexport enum A {\n A,\n B,\n C,\n}\n'],
|
||||||
|
{
|
||||||
|
type: "application/typescript",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
const a = await import(url);
|
||||||
|
|
||||||
|
console.log(a.a);
|
||||||
|
console.log(a.A);
|
||||||
|
console.log(a.A.A);
|
3
cli/tests/import_blob_url.ts.out
Normal file
3
cli/tests/import_blob_url.ts.out
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
a
|
||||||
|
{ "0": "A", "1": "B", "2": "C", A: 0, B: 1, C: 2 }
|
||||||
|
0
|
13
cli/tests/import_blob_url_error_stack.ts
Normal file
13
cli/tests/import_blob_url_error_stack.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
const blob = new Blob(
|
||||||
|
[
|
||||||
|
"enum A {\n A,\n B,\n C,\n }\n \n export function a() {\n throw new Error(`Hello ${A.C}`);\n }\n ",
|
||||||
|
],
|
||||||
|
{
|
||||||
|
type: "application/typescript",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
const { a } = await import(url);
|
||||||
|
|
||||||
|
a();
|
6
cli/tests/import_blob_url_error_stack.ts.out
Normal file
6
cli/tests/import_blob_url_error_stack.ts.out
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[WILDCARD]error: Uncaught (in promise) Error: Hello 2
|
||||||
|
throw new Error(`Hello ${A.C}`);
|
||||||
|
^
|
||||||
|
at a (blob:null/[WILDCARD]:8:10)
|
||||||
|
at file:///[WILDCARD]/cli/tests/import_blob_url_error_stack.ts:13:1
|
||||||
|
[WILDCARD]
|
8
cli/tests/import_blob_url_import_relative.ts
Normal file
8
cli/tests/import_blob_url_import_relative.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
const blob = new Blob(['export { a } from "./a.ts";'], {
|
||||||
|
type: "application/javascript",
|
||||||
|
});
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
const a = await import(url);
|
||||||
|
|
||||||
|
console.log(a);
|
4
cli/tests/import_blob_url_import_relative.ts.out
Normal file
4
cli/tests/import_blob_url_import_relative.ts.out
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
error: Uncaught (in promise) TypeError: invalid URL: relative URL with a cannot-be-a-base base
|
||||||
|
const a = await import(url);
|
||||||
|
^
|
||||||
|
at async file://[WILDCARD]/cli/tests/import_blob_url_import_relative.ts:6:11
|
11
cli/tests/import_blob_url_imports.ts
Normal file
11
cli/tests/import_blob_url_imports.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
const blob = new Blob(
|
||||||
|
[
|
||||||
|
'export { printHello } from "http://localhost:4545/cli/tests/subdir/mod2.ts"',
|
||||||
|
],
|
||||||
|
{ type: "application/javascript" },
|
||||||
|
);
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
const { printHello } = await import(url);
|
||||||
|
|
||||||
|
printHello();
|
1
cli/tests/import_blob_url_imports.ts.out
Normal file
1
cli/tests/import_blob_url_imports.ts.out
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Hello
|
16
cli/tests/import_blob_url_jsx.ts
Normal file
16
cli/tests/import_blob_url_jsx.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
const blob = new Blob(
|
||||||
|
["export default function() {\n return <div>Hello Deno!</div>\n}\n"],
|
||||||
|
{ type: "text/jsx" },
|
||||||
|
);
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
const { default: render } = await import(url);
|
||||||
|
|
||||||
|
// deno-lint-ignore no-explicit-any
|
||||||
|
(globalThis as any).React = {
|
||||||
|
createElement(...args: unknown[]) {
|
||||||
|
console.log(...args);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
render();
|
1
cli/tests/import_blob_url_jsx.ts.out
Normal file
1
cli/tests/import_blob_url_jsx.ts.out
Normal file
|
@ -0,0 +1 @@
|
||||||
|
div null Hello Deno!
|
|
@ -3683,6 +3683,34 @@ console.log("finish");
|
||||||
output: "import_dynamic_data_url.ts.out",
|
output: "import_dynamic_data_url.ts.out",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
itest!(import_blob_url_error_stack {
|
||||||
|
args: "run --quiet --reload import_blob_url_error_stack.ts",
|
||||||
|
output: "import_blob_url_error_stack.ts.out",
|
||||||
|
exit_code: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(import_blob_url_import_relative {
|
||||||
|
args: "run --quiet --reload import_blob_url_import_relative.ts",
|
||||||
|
output: "import_blob_url_import_relative.ts.out",
|
||||||
|
exit_code: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(import_blob_url_imports {
|
||||||
|
args: "run --quiet --reload import_blob_url_imports.ts",
|
||||||
|
output: "import_blob_url_imports.ts.out",
|
||||||
|
http_server: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(import_blob_url_jsx {
|
||||||
|
args: "run --quiet --reload import_blob_url_jsx.ts",
|
||||||
|
output: "import_blob_url_jsx.ts.out",
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(import_blob_url {
|
||||||
|
args: "run --quiet --reload import_blob_url.ts",
|
||||||
|
output: "import_blob_url.ts.out",
|
||||||
|
});
|
||||||
|
|
||||||
itest!(import_file_with_colon {
|
itest!(import_file_with_colon {
|
||||||
args: "run --quiet --reload import_file_with_colon.ts",
|
args: "run --quiet --reload import_file_with_colon.ts",
|
||||||
output: "import_file_with_colon.ts.out",
|
output: "import_file_with_colon.ts.out",
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
error: Uncaught (in promise) TypeError: Unsupported scheme "xxx" for module "xxx:". Supported schemes: [
|
error: Uncaught (in promise) TypeError: Unsupported scheme "xxx" for module "xxx:". Supported schemes: [
|
||||||
"data",
|
"data",
|
||||||
|
"blob",
|
||||||
"file",
|
"file",
|
||||||
"http",
|
"http",
|
||||||
"https",
|
"https",
|
||||||
|
|
40
cli/tsc.rs
40
cli/tsc.rs
|
@ -110,6 +110,19 @@ fn hash_data_url(
|
||||||
format!("data:///{}{}", hash, media_type.as_ts_extension())
|
format!("data:///{}{}", hash, media_type.as_ts_extension())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hash_blob_url(
|
||||||
|
specifier: &ModuleSpecifier,
|
||||||
|
media_type: &MediaType,
|
||||||
|
) -> String {
|
||||||
|
assert_eq!(
|
||||||
|
specifier.scheme(),
|
||||||
|
"blob",
|
||||||
|
"Specifier must be a blob: specifier."
|
||||||
|
);
|
||||||
|
let hash = crate::checksum::gen(&[specifier.path().as_bytes()]);
|
||||||
|
format!("blob:///{}{}", hash, media_type.as_ts_extension())
|
||||||
|
}
|
||||||
|
|
||||||
/// tsc only supports `.ts`, `.tsx`, `.d.ts`, `.js`, or `.jsx` as root modules
|
/// tsc only supports `.ts`, `.tsx`, `.d.ts`, `.js`, or `.jsx` as root modules
|
||||||
/// and so we have to detect the apparent media type based on extensions it
|
/// and so we have to detect the apparent media type based on extensions it
|
||||||
/// supports.
|
/// supports.
|
||||||
|
@ -378,15 +391,19 @@ fn resolve(state: &mut State, args: Value) -> Result<Value, AnyError> {
|
||||||
resolved_specifier
|
resolved_specifier
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let resolved_specifier_str = if resolved_specifier.scheme() == "data"
|
let resolved_specifier_str = match resolved_specifier.scheme() {
|
||||||
{
|
"data" | "blob" => {
|
||||||
let specifier_str = hash_data_url(&resolved_specifier, &media_type);
|
let specifier_str = if resolved_specifier.scheme() == "data" {
|
||||||
|
hash_data_url(&resolved_specifier, &media_type)
|
||||||
|
} else {
|
||||||
|
hash_blob_url(&resolved_specifier, &media_type)
|
||||||
|
};
|
||||||
state
|
state
|
||||||
.data_url_map
|
.data_url_map
|
||||||
.insert(specifier_str.clone(), resolved_specifier);
|
.insert(specifier_str.clone(), resolved_specifier);
|
||||||
specifier_str
|
specifier_str
|
||||||
} else {
|
}
|
||||||
resolved_specifier.to_string()
|
_ => resolved_specifier.to_string(),
|
||||||
};
|
};
|
||||||
resolved.push((
|
resolved.push((
|
||||||
resolved_specifier_str,
|
resolved_specifier_str,
|
||||||
|
@ -439,12 +456,17 @@ pub fn exec(request: Request) -> Result<Response, AnyError> {
|
||||||
let root_names: Vec<String> = request
|
let root_names: Vec<String> = request
|
||||||
.root_names
|
.root_names
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(s, mt)| {
|
.map(|(s, mt)| match s.scheme() {
|
||||||
if s.scheme() == "data" {
|
"data" | "blob" => {
|
||||||
let specifier_str = hash_data_url(s, mt);
|
let specifier_str = if s.scheme() == "data" {
|
||||||
|
hash_data_url(&s, &mt)
|
||||||
|
} else {
|
||||||
|
hash_blob_url(&s, &mt)
|
||||||
|
};
|
||||||
data_url_map.insert(specifier_str.clone(), s.clone());
|
data_url_map.insert(specifier_str.clone(), s.clone());
|
||||||
specifier_str
|
specifier_str
|
||||||
} else {
|
}
|
||||||
|
_ => {
|
||||||
let ext_media_type = get_tsc_media_type(s);
|
let ext_media_type = get_tsc_media_type(s);
|
||||||
if mt != &ext_media_type {
|
if mt != &ext_media_type {
|
||||||
let new_specifier = format!("{}{}", s, mt.as_ts_extension());
|
let new_specifier = format!("{}{}", s, mt.as_ts_extension());
|
||||||
|
|
63
op_crates/file/03_blob_url.js
Normal file
63
op_crates/file/03_blob_url.js
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
/// <reference no-default-lib="true" />
|
||||||
|
/// <reference path="../../core/lib.deno_core.d.ts" />
|
||||||
|
/// <reference path="../webidl/internal.d.ts" />
|
||||||
|
/// <reference path="../web/internal.d.ts" />
|
||||||
|
/// <reference path="../web/lib.deno_web.d.ts" />
|
||||||
|
/// <reference path="../url/internal.d.ts" />
|
||||||
|
/// <reference path="../url/lib.deno_url.d.ts" />
|
||||||
|
/// <reference path="./internal.d.ts" />
|
||||||
|
/// <reference path="./lib.deno_file.d.ts" />
|
||||||
|
/// <reference lib="esnext" />
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
((window) => {
|
||||||
|
const core = Deno.core;
|
||||||
|
// const webidl = window.__bootstrap.webidl;
|
||||||
|
const { _byteSequence } = window.__bootstrap.file;
|
||||||
|
const { URL } = window.__bootstrap.url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Blob} blob
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function createObjectURL(blob) {
|
||||||
|
// const prefix = "Failed to execute 'createObjectURL' on 'URL'";
|
||||||
|
// webidl.requiredArguments(arguments.length, 1, { prefix });
|
||||||
|
// blob = webidl.converters["Blob"](blob, {
|
||||||
|
// context: "Argument 1",
|
||||||
|
// prefix,
|
||||||
|
// });
|
||||||
|
|
||||||
|
const url = core.jsonOpSync(
|
||||||
|
"op_file_create_object_url",
|
||||||
|
blob.type,
|
||||||
|
blob[_byteSequence],
|
||||||
|
);
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} url
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function revokeObjectURL(url) {
|
||||||
|
// const prefix = "Failed to execute 'revokeObjectURL' on 'URL'";
|
||||||
|
// webidl.requiredArguments(arguments.length, 1, { prefix });
|
||||||
|
// url = webidl.converters["DOMString"](url, {
|
||||||
|
// context: "Argument 1",
|
||||||
|
// prefix,
|
||||||
|
// });
|
||||||
|
|
||||||
|
core.jsonOpSync(
|
||||||
|
"op_file_revoke_object_url",
|
||||||
|
url,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
URL.createObjectURL = createObjectURL;
|
||||||
|
URL.revokeObjectURL = revokeObjectURL;
|
||||||
|
})(globalThis);
|
|
@ -15,3 +15,4 @@ path = "lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
deno_core = { version = "0.83.0", path = "../../core" }
|
deno_core = { version = "0.83.0", path = "../../core" }
|
||||||
|
uuid = { version = "0.8.2", features = ["v4"] }
|
||||||
|
|
|
@ -1,7 +1,85 @@
|
||||||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use deno_core::error::null_opbuf;
|
||||||
|
use deno_core::error::AnyError;
|
||||||
|
use deno_core::url::Url;
|
||||||
use deno_core::JsRuntime;
|
use deno_core::JsRuntime;
|
||||||
|
use deno_core::ModuleSpecifier;
|
||||||
|
use deno_core::ZeroCopyBuf;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Blob {
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
pub media_type: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Location(pub Url);
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct BlobUrlStore(Arc<Mutex<HashMap<Url, Blob>>>);
|
||||||
|
|
||||||
|
impl BlobUrlStore {
|
||||||
|
pub fn get(&self, url: &ModuleSpecifier) -> Result<Option<Blob>, AnyError> {
|
||||||
|
let blob_store = self.0.lock().unwrap();
|
||||||
|
Ok(blob_store.get(url).cloned())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&self, blob: Blob, maybe_location: Option<Url>) -> Url {
|
||||||
|
let origin = if let Some(location) = maybe_location {
|
||||||
|
location.origin().ascii_serialization()
|
||||||
|
} else {
|
||||||
|
"null".to_string()
|
||||||
|
};
|
||||||
|
let id = Uuid::new_v4();
|
||||||
|
let url = Url::parse(&format!("blob:{}/{}", origin, id)).unwrap();
|
||||||
|
|
||||||
|
let mut blob_store = self.0.lock().unwrap();
|
||||||
|
blob_store.insert(url.clone(), blob);
|
||||||
|
|
||||||
|
url
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&self, url: &ModuleSpecifier) {
|
||||||
|
let mut blob_store = self.0.lock().unwrap();
|
||||||
|
blob_store.remove(&url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn op_file_create_object_url(
|
||||||
|
state: &mut deno_core::OpState,
|
||||||
|
media_type: String,
|
||||||
|
zero_copy: Option<ZeroCopyBuf>,
|
||||||
|
) -> Result<String, AnyError> {
|
||||||
|
let data = zero_copy.ok_or_else(null_opbuf)?;
|
||||||
|
let blob = Blob {
|
||||||
|
data: data.to_vec(),
|
||||||
|
media_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
let maybe_location = state.try_borrow::<Location>();
|
||||||
|
let blob_store = state.borrow::<BlobUrlStore>();
|
||||||
|
|
||||||
|
let url =
|
||||||
|
blob_store.insert(blob, maybe_location.map(|location| location.0.clone()));
|
||||||
|
|
||||||
|
Ok(url.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn op_file_revoke_object_url(
|
||||||
|
state: &mut deno_core::OpState,
|
||||||
|
url: String,
|
||||||
|
_zero_copy: Option<ZeroCopyBuf>,
|
||||||
|
) -> Result<(), AnyError> {
|
||||||
|
let url = Url::parse(&url)?;
|
||||||
|
let blob_store = state.borrow::<BlobUrlStore>();
|
||||||
|
blob_store.remove(&url);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Load and execute the javascript code.
|
/// Load and execute the javascript code.
|
||||||
pub fn init(isolate: &mut JsRuntime) {
|
pub fn init(isolate: &mut JsRuntime) {
|
||||||
|
@ -11,6 +89,10 @@ pub fn init(isolate: &mut JsRuntime) {
|
||||||
"deno:op_crates/file/02_filereader.js",
|
"deno:op_crates/file/02_filereader.js",
|
||||||
include_str!("02_filereader.js"),
|
include_str!("02_filereader.js"),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"deno:op_crates/file/03_blob_url.js",
|
||||||
|
include_str!("03_blob_url.js"),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
for (url, source_code) in files {
|
for (url, source_code) in files {
|
||||||
isolate.execute(url, source_code).unwrap();
|
isolate.execute(url, source_code).unwrap();
|
||||||
|
|
|
@ -389,14 +389,6 @@
|
||||||
toJSON() {
|
toJSON() {
|
||||||
return this.href;
|
return this.href;
|
||||||
}
|
}
|
||||||
|
|
||||||
static createObjectURL() {
|
|
||||||
throw new Error("Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
static revokeObjectURL() {
|
|
||||||
throw new Error("Not implemented");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.__bootstrap.url = {
|
window.__bootstrap.url = {
|
||||||
|
|
4
op_crates/url/lib.deno_url.d.ts
vendored
4
op_crates/url/lib.deno_url.d.ts
vendored
|
@ -155,8 +155,8 @@ declare class URLSearchParams {
|
||||||
/** The URL interface represents an object providing static methods used for creating object URLs. */
|
/** The URL interface represents an object providing static methods used for creating object URLs. */
|
||||||
declare class URL {
|
declare class URL {
|
||||||
constructor(url: string, base?: string | URL);
|
constructor(url: string, base?: string | URL);
|
||||||
createObjectURL(object: any): string;
|
static createObjectURL(blob: Blob): string;
|
||||||
revokeObjectURL(url: string): void;
|
static revokeObjectURL(url: string): void;
|
||||||
|
|
||||||
hash: string;
|
hash: string;
|
||||||
host: string;
|
host: string;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::FsModuleLoader;
|
use deno_core::FsModuleLoader;
|
||||||
|
use deno_runtime::deno_file::BlobUrlStore;
|
||||||
use deno_runtime::permissions::Permissions;
|
use deno_runtime::permissions::Permissions;
|
||||||
use deno_runtime::worker::MainWorker;
|
use deno_runtime::worker::MainWorker;
|
||||||
use deno_runtime::worker::WorkerOptions;
|
use deno_runtime::worker::WorkerOptions;
|
||||||
|
@ -39,6 +40,7 @@ async fn main() -> Result<(), AnyError> {
|
||||||
no_color: false,
|
no_color: false,
|
||||||
get_error_class_fn: Some(&get_error_class_name),
|
get_error_class_fn: Some(&get_error_class_name),
|
||||||
location: None,
|
location: None,
|
||||||
|
blob_url_store: BlobUrlStore::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let js_path =
|
let js_path =
|
||||||
|
|
31
runtime/ops/file.rs
Normal file
31
runtime/ops/file.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||||
|
use deno_core::url::Url;
|
||||||
|
use deno_file::op_file_create_object_url;
|
||||||
|
use deno_file::op_file_revoke_object_url;
|
||||||
|
use deno_file::BlobUrlStore;
|
||||||
|
use deno_file::Location;
|
||||||
|
|
||||||
|
pub fn init(
|
||||||
|
rt: &mut deno_core::JsRuntime,
|
||||||
|
blob_url_store: BlobUrlStore,
|
||||||
|
maybe_location: Option<Url>,
|
||||||
|
) {
|
||||||
|
{
|
||||||
|
let op_state = rt.op_state();
|
||||||
|
let mut op_state = op_state.borrow_mut();
|
||||||
|
op_state.put(blob_url_store);
|
||||||
|
if let Some(location) = maybe_location {
|
||||||
|
op_state.put(Location(location));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super::reg_json_sync(
|
||||||
|
rt,
|
||||||
|
"op_file_create_object_url",
|
||||||
|
op_file_create_object_url,
|
||||||
|
);
|
||||||
|
super::reg_json_sync(
|
||||||
|
rt,
|
||||||
|
"op_file_revoke_object_url",
|
||||||
|
op_file_revoke_object_url,
|
||||||
|
);
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
pub mod crypto;
|
pub mod crypto;
|
||||||
pub mod fetch;
|
pub mod fetch;
|
||||||
|
pub mod file;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod fs_events;
|
pub mod fs_events;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
|
|
|
@ -587,6 +587,7 @@ impl Permissions {
|
||||||
))),
|
))),
|
||||||
},
|
},
|
||||||
"data" => Ok(()),
|
"data" => Ok(()),
|
||||||
|
"blob" => Ok(()),
|
||||||
_ => self.net.check_url(specifier),
|
_ => self.net.check_url(specifier),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ use deno_core::JsRuntime;
|
||||||
use deno_core::ModuleLoader;
|
use deno_core::ModuleLoader;
|
||||||
use deno_core::ModuleSpecifier;
|
use deno_core::ModuleSpecifier;
|
||||||
use deno_core::RuntimeOptions;
|
use deno_core::RuntimeOptions;
|
||||||
|
use deno_file::BlobUrlStore;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -155,6 +156,7 @@ pub struct WebWorkerOptions {
|
||||||
/// Sets `Deno.noColor` in JS runtime.
|
/// Sets `Deno.noColor` in JS runtime.
|
||||||
pub no_color: bool,
|
pub no_color: bool,
|
||||||
pub get_error_class_fn: Option<GetErrorClassFn>,
|
pub get_error_class_fn: Option<GetErrorClassFn>,
|
||||||
|
pub blob_url_store: BlobUrlStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebWorker {
|
impl WebWorker {
|
||||||
|
@ -217,7 +219,7 @@ impl WebWorker {
|
||||||
}
|
}
|
||||||
|
|
||||||
ops::web_worker::init(js_runtime, sender.clone(), handle);
|
ops::web_worker::init(js_runtime, sender.clone(), handle);
|
||||||
ops::runtime::init(js_runtime, main_module);
|
ops::runtime::init(js_runtime, main_module.clone());
|
||||||
ops::fetch::init(
|
ops::fetch::init(
|
||||||
js_runtime,
|
js_runtime,
|
||||||
options.user_agent.clone(),
|
options.user_agent.clone(),
|
||||||
|
@ -232,6 +234,11 @@ impl WebWorker {
|
||||||
ops::reg_json_sync(js_runtime, "op_close", deno_core::op_close);
|
ops::reg_json_sync(js_runtime, "op_close", deno_core::op_close);
|
||||||
ops::reg_json_sync(js_runtime, "op_resources", deno_core::op_resources);
|
ops::reg_json_sync(js_runtime, "op_resources", deno_core::op_resources);
|
||||||
ops::url::init(js_runtime);
|
ops::url::init(js_runtime);
|
||||||
|
ops::file::init(
|
||||||
|
js_runtime,
|
||||||
|
options.blob_url_store.clone(),
|
||||||
|
Some(main_module),
|
||||||
|
);
|
||||||
ops::io::init(js_runtime);
|
ops::io::init(js_runtime);
|
||||||
ops::webgpu::init(js_runtime);
|
ops::webgpu::init(js_runtime);
|
||||||
ops::websocket::init(
|
ops::websocket::init(
|
||||||
|
@ -518,6 +525,7 @@ mod tests {
|
||||||
ts_version: "x".to_string(),
|
ts_version: "x".to_string(),
|
||||||
no_color: true,
|
no_color: true,
|
||||||
get_error_class_fn: None,
|
get_error_class_fn: None,
|
||||||
|
blob_url_store: BlobUrlStore::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut worker = WebWorker::from_options(
|
let mut worker = WebWorker::from_options(
|
||||||
|
|
|
@ -21,6 +21,7 @@ use deno_core::ModuleId;
|
||||||
use deno_core::ModuleLoader;
|
use deno_core::ModuleLoader;
|
||||||
use deno_core::ModuleSpecifier;
|
use deno_core::ModuleSpecifier;
|
||||||
use deno_core::RuntimeOptions;
|
use deno_core::RuntimeOptions;
|
||||||
|
use deno_file::BlobUrlStore;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -66,6 +67,7 @@ pub struct WorkerOptions {
|
||||||
pub no_color: bool,
|
pub no_color: bool,
|
||||||
pub get_error_class_fn: Option<GetErrorClassFn>,
|
pub get_error_class_fn: Option<GetErrorClassFn>,
|
||||||
pub location: Option<Url>,
|
pub location: Option<Url>,
|
||||||
|
pub blob_url_store: BlobUrlStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MainWorker {
|
impl MainWorker {
|
||||||
|
@ -129,6 +131,11 @@ impl MainWorker {
|
||||||
ops::reg_json_sync(js_runtime, "op_close", deno_core::op_close);
|
ops::reg_json_sync(js_runtime, "op_close", deno_core::op_close);
|
||||||
ops::reg_json_sync(js_runtime, "op_resources", deno_core::op_resources);
|
ops::reg_json_sync(js_runtime, "op_resources", deno_core::op_resources);
|
||||||
ops::url::init(js_runtime);
|
ops::url::init(js_runtime);
|
||||||
|
ops::file::init(
|
||||||
|
js_runtime,
|
||||||
|
options.blob_url_store.clone(),
|
||||||
|
options.location.clone(),
|
||||||
|
);
|
||||||
ops::fs_events::init(js_runtime);
|
ops::fs_events::init(js_runtime);
|
||||||
ops::fs::init(js_runtime);
|
ops::fs::init(js_runtime);
|
||||||
ops::io::init(js_runtime);
|
ops::io::init(js_runtime);
|
||||||
|
@ -298,6 +305,7 @@ mod tests {
|
||||||
no_color: true,
|
no_color: true,
|
||||||
get_error_class_fn: None,
|
get_error_class_fn: None,
|
||||||
location: None,
|
location: None,
|
||||||
|
blob_url_store: BlobUrlStore::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
MainWorker::from_options(main_module, permissions, &options)
|
MainWorker::from_options(main_module, permissions, &options)
|
||||||
|
|
Loading…
Reference in a new issue