deno_runtime/
snapshot.rs

1// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2
3use crate::ops;
4use crate::ops::bootstrap::SnapshotOptions;
5use crate::shared::maybe_transpile_source;
6use crate::shared::runtime;
7use deno_cache::SqliteBackedCache;
8use deno_core::snapshot::*;
9use deno_core::v8;
10use deno_core::Extension;
11use deno_http::DefaultHttpPropertyExtractor;
12use deno_io::fs::FsError;
13use deno_permissions::PermissionCheckError;
14use std::borrow::Cow;
15use std::io::Write;
16use std::path::Path;
17use std::path::PathBuf;
18use std::rc::Rc;
19use std::sync::Arc;
20
21#[derive(Clone)]
22struct Permissions;
23
24impl deno_websocket::WebSocketPermissions for Permissions {
25  fn check_net_url(
26    &mut self,
27    _url: &deno_core::url::Url,
28    _api_name: &str,
29  ) -> Result<(), PermissionCheckError> {
30    unreachable!("snapshotting!")
31  }
32}
33
34impl deno_web::TimersPermission for Permissions {
35  fn allow_hrtime(&mut self) -> bool {
36    unreachable!("snapshotting!")
37  }
38}
39
40impl deno_fetch::FetchPermissions for Permissions {
41  fn check_net_url(
42    &mut self,
43    _url: &deno_core::url::Url,
44    _api_name: &str,
45  ) -> Result<(), PermissionCheckError> {
46    unreachable!("snapshotting!")
47  }
48
49  fn check_read<'a>(
50    &mut self,
51    _p: &'a Path,
52    _api_name: &str,
53  ) -> Result<Cow<'a, Path>, PermissionCheckError> {
54    unreachable!("snapshotting!")
55  }
56}
57
58impl deno_ffi::FfiPermissions for Permissions {
59  fn check_partial_no_path(&mut self) -> Result<(), PermissionCheckError> {
60    unreachable!("snapshotting!")
61  }
62
63  fn check_partial_with_path(
64    &mut self,
65    _path: &str,
66  ) -> Result<PathBuf, PermissionCheckError> {
67    unreachable!("snapshotting!")
68  }
69}
70
71impl deno_napi::NapiPermissions for Permissions {
72  fn check(&mut self, _path: &str) -> Result<PathBuf, PermissionCheckError> {
73    unreachable!("snapshotting!")
74  }
75}
76
77impl deno_node::NodePermissions for Permissions {
78  fn check_net_url(
79    &mut self,
80    _url: &deno_core::url::Url,
81    _api_name: &str,
82  ) -> Result<(), PermissionCheckError> {
83    unreachable!("snapshotting!")
84  }
85  fn check_net(
86    &mut self,
87    _host: (&str, Option<u16>),
88    _api_name: &str,
89  ) -> Result<(), PermissionCheckError> {
90    unreachable!("snapshotting!")
91  }
92  fn check_read_path<'a>(
93    &mut self,
94    _path: &'a Path,
95  ) -> Result<Cow<'a, Path>, PermissionCheckError> {
96    unreachable!("snapshotting!")
97  }
98  fn check_read_with_api_name(
99    &mut self,
100    _p: &str,
101    _api_name: Option<&str>,
102  ) -> Result<PathBuf, PermissionCheckError> {
103    unreachable!("snapshotting!")
104  }
105  fn query_read_all(&mut self) -> bool {
106    unreachable!("snapshotting!")
107  }
108  fn check_write_with_api_name(
109    &mut self,
110    _p: &str,
111    _api_name: Option<&str>,
112  ) -> Result<PathBuf, PermissionCheckError> {
113    unreachable!("snapshotting!")
114  }
115  fn check_sys(
116    &mut self,
117    _kind: &str,
118    _api_name: &str,
119  ) -> Result<(), PermissionCheckError> {
120    unreachable!("snapshotting!")
121  }
122}
123
124impl deno_net::NetPermissions for Permissions {
125  fn check_net<T: AsRef<str>>(
126    &mut self,
127    _host: &(T, Option<u16>),
128    _api_name: &str,
129  ) -> Result<(), PermissionCheckError> {
130    unreachable!("snapshotting!")
131  }
132
133  fn check_read(
134    &mut self,
135    _p: &str,
136    _api_name: &str,
137  ) -> Result<PathBuf, PermissionCheckError> {
138    unreachable!("snapshotting!")
139  }
140
141  fn check_write(
142    &mut self,
143    _p: &str,
144    _api_name: &str,
145  ) -> Result<PathBuf, PermissionCheckError> {
146    unreachable!("snapshotting!")
147  }
148
149  fn check_write_path<'a>(
150    &mut self,
151    _p: &'a Path,
152    _api_name: &str,
153  ) -> Result<Cow<'a, Path>, PermissionCheckError> {
154    unreachable!("snapshotting!")
155  }
156}
157
158impl deno_fs::FsPermissions for Permissions {
159  fn check_open<'a>(
160    &mut self,
161    _resolved: bool,
162    _read: bool,
163    _write: bool,
164    _path: &'a Path,
165    _api_name: &str,
166  ) -> Result<Cow<'a, Path>, FsError> {
167    unreachable!("snapshotting!")
168  }
169
170  fn check_read(
171    &mut self,
172    _path: &str,
173    _api_name: &str,
174  ) -> Result<PathBuf, PermissionCheckError> {
175    unreachable!("snapshotting!")
176  }
177
178  fn check_read_all(
179    &mut self,
180    _api_name: &str,
181  ) -> Result<(), PermissionCheckError> {
182    unreachable!("snapshotting!")
183  }
184
185  fn check_read_blind(
186    &mut self,
187    _path: &Path,
188    _display: &str,
189    _api_name: &str,
190  ) -> Result<(), PermissionCheckError> {
191    unreachable!("snapshotting!")
192  }
193
194  fn check_write(
195    &mut self,
196    _path: &str,
197    _api_name: &str,
198  ) -> Result<PathBuf, PermissionCheckError> {
199    unreachable!("snapshotting!")
200  }
201
202  fn check_write_partial(
203    &mut self,
204    _path: &str,
205    _api_name: &str,
206  ) -> Result<PathBuf, PermissionCheckError> {
207    unreachable!("snapshotting!")
208  }
209
210  fn check_write_all(
211    &mut self,
212    _api_name: &str,
213  ) -> Result<(), PermissionCheckError> {
214    unreachable!("snapshotting!")
215  }
216
217  fn check_write_blind(
218    &mut self,
219    _path: &Path,
220    _display: &str,
221    _api_name: &str,
222  ) -> Result<(), PermissionCheckError> {
223    unreachable!("snapshotting!")
224  }
225
226  fn check_read_path<'a>(
227    &mut self,
228    _path: &'a Path,
229    _api_name: &str,
230  ) -> Result<Cow<'a, Path>, PermissionCheckError> {
231    unreachable!("snapshotting!")
232  }
233
234  fn check_write_path<'a>(
235    &mut self,
236    _path: &'a Path,
237    _api_name: &str,
238  ) -> Result<Cow<'a, Path>, PermissionCheckError> {
239    unreachable!("snapshotting!")
240  }
241}
242
243impl deno_kv::sqlite::SqliteDbHandlerPermissions for Permissions {
244  fn check_read(
245    &mut self,
246    _path: &str,
247    _api_name: &str,
248  ) -> Result<PathBuf, PermissionCheckError> {
249    unreachable!("snapshotting!")
250  }
251
252  fn check_write<'a>(
253    &mut self,
254    _path: &'a Path,
255    _api_name: &str,
256  ) -> Result<Cow<'a, Path>, PermissionCheckError> {
257    unreachable!("snapshotting!")
258  }
259}
260
261pub fn create_runtime_snapshot(
262  snapshot_path: PathBuf,
263  snapshot_options: SnapshotOptions,
264  // NOTE: For embedders that wish to add additional extensions to the snapshot
265  custom_extensions: Vec<Extension>,
266) {
267  // NOTE(bartlomieju): ordering is important here, keep it in sync with
268  // `runtime/worker.rs`, `runtime/web_worker.rs` and `runtime/snapshot.rs`!
269  let fs = std::sync::Arc::new(deno_fs::RealFs);
270  let mut extensions: Vec<Extension> = vec![
271    deno_telemetry::deno_telemetry::init_ops_and_esm(),
272    deno_webidl::deno_webidl::init_ops_and_esm(),
273    deno_console::deno_console::init_ops_and_esm(),
274    deno_url::deno_url::init_ops_and_esm(),
275    deno_web::deno_web::init_ops_and_esm::<Permissions>(
276      Default::default(),
277      Default::default(),
278    ),
279    deno_webgpu::deno_webgpu::init_ops_and_esm(),
280    deno_canvas::deno_canvas::init_ops_and_esm(),
281    deno_fetch::deno_fetch::init_ops_and_esm::<Permissions>(Default::default()),
282    deno_cache::deno_cache::init_ops_and_esm::<SqliteBackedCache>(None),
283    deno_websocket::deno_websocket::init_ops_and_esm::<Permissions>(
284      "".to_owned(),
285      None,
286      None,
287    ),
288    deno_webstorage::deno_webstorage::init_ops_and_esm(None),
289    deno_crypto::deno_crypto::init_ops_and_esm(None),
290    deno_broadcast_channel::deno_broadcast_channel::init_ops_and_esm(
291      deno_broadcast_channel::InMemoryBroadcastChannel::default(),
292    ),
293    deno_ffi::deno_ffi::init_ops_and_esm::<Permissions>(),
294    deno_net::deno_net::init_ops_and_esm::<Permissions>(None, None),
295    deno_tls::deno_tls::init_ops_and_esm(),
296    deno_kv::deno_kv::init_ops_and_esm(
297      deno_kv::sqlite::SqliteDbHandler::<Permissions>::new(None, None),
298      deno_kv::KvConfig::builder().build(),
299    ),
300    deno_cron::deno_cron::init_ops_and_esm(
301      deno_cron::local::LocalCronHandler::new(),
302    ),
303    deno_napi::deno_napi::init_ops_and_esm::<Permissions>(),
304    deno_http::deno_http::init_ops_and_esm::<DefaultHttpPropertyExtractor>(
305      deno_http::Options::default(),
306    ),
307    deno_io::deno_io::init_ops_and_esm(Default::default()),
308    deno_fs::deno_fs::init_ops_and_esm::<Permissions>(fs.clone()),
309    deno_node::deno_node::init_ops_and_esm::<Permissions>(None, fs.clone()),
310    runtime::init_ops_and_esm(),
311    ops::runtime::deno_runtime::init_ops("deno:runtime".parse().unwrap()),
312    ops::worker_host::deno_worker_host::init_ops(
313      Arc::new(|_| unreachable!("not used in snapshot.")),
314      None,
315    ),
316    ops::fs_events::deno_fs_events::init_ops(),
317    ops::os::deno_os::init_ops(Default::default()),
318    ops::permissions::deno_permissions::init_ops(),
319    ops::process::deno_process::init_ops(None),
320    ops::signal::deno_signal::init_ops(),
321    ops::tty::deno_tty::init_ops(),
322    ops::http::deno_http_runtime::init_ops(),
323    ops::bootstrap::deno_bootstrap::init_ops(Some(snapshot_options)),
324    ops::web_worker::deno_web_worker::init_ops(),
325  ];
326  extensions.extend(custom_extensions);
327
328  let output = create_snapshot(
329    CreateSnapshotOptions {
330      cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"),
331      startup_snapshot: None,
332      extensions,
333      extension_transpiler: Some(Rc::new(|specifier, source| {
334        maybe_transpile_source(specifier, source)
335      })),
336      with_runtime_cb: Some(Box::new(|rt| {
337        let isolate = rt.v8_isolate();
338        let scope = &mut v8::HandleScope::new(isolate);
339
340        let tmpl = deno_node::init_global_template(
341          scope,
342          deno_node::ContextInitMode::ForSnapshot,
343        );
344        let ctx = deno_node::create_v8_context(
345          scope,
346          tmpl,
347          deno_node::ContextInitMode::ForSnapshot,
348          std::ptr::null_mut(),
349        );
350        assert_eq!(scope.add_context(ctx), deno_node::VM_CONTEXT_INDEX);
351      })),
352      skip_op_registration: false,
353    },
354    None,
355  )
356  .unwrap();
357  let mut snapshot = std::fs::File::create(snapshot_path).unwrap();
358  snapshot.write_all(&output.output).unwrap();
359
360  #[allow(clippy::print_stdout)]
361  for path in output.files_loaded_during_snapshot {
362    println!("cargo:rerun-if-changed={}", path.display());
363  }
364}