summaryrefslogtreecommitdiff
path: root/cli/tools/serve.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tools/serve.rs')
-rw-r--r--cli/tools/serve.rs192
1 files changed, 192 insertions, 0 deletions
diff --git a/cli/tools/serve.rs b/cli/tools/serve.rs
new file mode 100644
index 000000000..24666b8f6
--- /dev/null
+++ b/cli/tools/serve.rs
@@ -0,0 +1,192 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+
+use std::sync::Arc;
+
+use deno_core::error::AnyError;
+use deno_core::futures::TryFutureExt;
+use deno_core::ModuleSpecifier;
+use deno_runtime::deno_permissions::Permissions;
+use deno_runtime::deno_permissions::PermissionsContainer;
+
+use super::run::check_permission_before_script;
+use super::run::maybe_npm_install;
+use crate::args::Flags;
+use crate::args::ServeFlags;
+use crate::args::WatchFlagsWithPaths;
+use crate::factory::CliFactory;
+use crate::util::file_watcher::WatcherRestartMode;
+use crate::worker::CliMainWorkerFactory;
+
+pub async fn serve(
+ flags: Arc<Flags>,
+ serve_flags: ServeFlags,
+) -> Result<i32, AnyError> {
+ check_permission_before_script(&flags);
+
+ if let Some(watch_flags) = serve_flags.watch {
+ return serve_with_watch(flags, watch_flags, serve_flags.worker_count)
+ .await;
+ }
+
+ let factory = CliFactory::from_flags(flags);
+ let cli_options = factory.cli_options()?;
+ let deno_dir = factory.deno_dir()?;
+ let http_client = factory.http_client_provider();
+
+ // Run a background task that checks for available upgrades or output
+ // if an earlier run of this background task found a new version of Deno.
+ #[cfg(feature = "upgrade")]
+ super::upgrade::check_for_upgrades(
+ http_client.clone(),
+ deno_dir.upgrade_check_file_path(),
+ );
+
+ let main_module = cli_options.resolve_main_module()?;
+
+ maybe_npm_install(&factory).await?;
+
+ let permissions = PermissionsContainer::new(Permissions::from_options(
+ &cli_options.permissions_options()?,
+ )?);
+ let worker_factory = factory.create_cli_main_worker_factory().await?;
+
+ do_serve(
+ worker_factory,
+ main_module,
+ permissions,
+ serve_flags.worker_count,
+ false,
+ )
+ .await
+}
+
+async fn do_serve(
+ worker_factory: CliMainWorkerFactory,
+ main_module: ModuleSpecifier,
+ permissions: PermissionsContainer,
+ worker_count: Option<usize>,
+ hmr: bool,
+) -> Result<i32, AnyError> {
+ let mut worker = worker_factory
+ .create_main_worker(
+ deno_runtime::WorkerExecutionMode::Serve {
+ is_main: true,
+ worker_count,
+ },
+ main_module.clone(),
+ permissions.clone(),
+ )
+ .await?;
+ let worker_count = match worker_count {
+ None | Some(1) => return worker.run().await,
+ Some(c) => c,
+ };
+
+ let main = deno_core::unsync::spawn(async move { worker.run().await });
+
+ let extra_workers = worker_count.saturating_sub(1);
+
+ let mut channels = Vec::with_capacity(extra_workers);
+ for i in 0..extra_workers {
+ let worker_factory = worker_factory.clone();
+ let main_module = main_module.clone();
+ let permissions = permissions.clone();
+ let (tx, rx) = tokio::sync::oneshot::channel();
+ channels.push(rx);
+ std::thread::Builder::new()
+ .name(format!("serve-worker-{i}"))
+ .spawn(move || {
+ deno_runtime::tokio_util::create_and_run_current_thread(async move {
+ let result =
+ run_worker(i, worker_factory, main_module, permissions, hmr).await;
+ let _ = tx.send(result);
+ });
+ })?;
+ }
+
+ let (main_result, worker_results) = tokio::try_join!(
+ main.map_err(AnyError::from),
+ deno_core::futures::future::try_join_all(
+ channels.into_iter().map(|r| r.map_err(AnyError::from))
+ )
+ )?;
+
+ let mut exit_code = main_result?;
+ for res in worker_results {
+ let ret = res?;
+ if ret != 0 && exit_code == 0 {
+ exit_code = ret;
+ }
+ }
+ Ok(exit_code)
+
+ // main.await?
+}
+
+async fn run_worker(
+ worker_count: usize,
+ worker_factory: CliMainWorkerFactory,
+ main_module: ModuleSpecifier,
+ permissions: PermissionsContainer,
+ hmr: bool,
+) -> Result<i32, AnyError> {
+ let mut worker = worker_factory
+ .create_main_worker(
+ deno_runtime::WorkerExecutionMode::Serve {
+ is_main: false,
+ worker_count: Some(worker_count),
+ },
+ main_module,
+ permissions,
+ )
+ .await?;
+ if hmr {
+ worker.run_for_watcher().await?;
+ Ok(0)
+ } else {
+ worker.run().await
+ }
+}
+
+async fn serve_with_watch(
+ flags: Arc<Flags>,
+ watch_flags: WatchFlagsWithPaths,
+ worker_count: Option<usize>,
+) -> Result<i32, AnyError> {
+ let hmr = watch_flags.hmr;
+ crate::util::file_watcher::watch_recv(
+ flags,
+ crate::util::file_watcher::PrintConfig::new_with_banner(
+ if watch_flags.hmr { "HMR" } else { "Watcher" },
+ "Process",
+ !watch_flags.no_clear_screen,
+ ),
+ WatcherRestartMode::Automatic,
+ move |flags, watcher_communicator, _changed_paths| {
+ Ok(async move {
+ let factory = CliFactory::from_flags_for_watcher(
+ flags,
+ watcher_communicator.clone(),
+ );
+ let cli_options = factory.cli_options()?;
+ let main_module = cli_options.resolve_main_module()?;
+
+ maybe_npm_install(&factory).await?;
+
+ let _ = watcher_communicator.watch_paths(cli_options.watch_paths());
+
+ let permissions = PermissionsContainer::new(Permissions::from_options(
+ &cli_options.permissions_options()?,
+ )?);
+ let worker_factory = factory.create_cli_main_worker_factory().await?;
+
+ do_serve(worker_factory, main_module, permissions, worker_count, hmr)
+ .await?;
+
+ Ok(())
+ })
+ },
+ )
+ .await?;
+ Ok(0)
+}